TS基础类型

TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用。

boolean

最基本的数据类型就是简单的 true/false 值,在 JavaScript 和 TypeScript 里叫做 boolean(其它语言中也一样)。

1
2
3
let isDone: boolean = false;
isDone = true;
// isDone = 2 // error

number

和 JavaScript 一样,TypeScript 里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript 还支持 ECMAScript 2015 中引入的二进制和八进制字面量。

1
2
3
4
let a1: number = 10; // 十进制
let a2: number = 0b1010; // 二进制
let a3: number = 0o12; // 八进制
let a4: number = 0xa; // 十六进制

string

JavaScript 程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用 string 表示文本数据类型。 和 JavaScript 一样,可以使用双引号(")或单引号(')表示字符串。

1
2
3
4
5
let name: string = "tom";
name = "jack";
// name = 12 // error
let age: number = 12;
const info = `My name is ${name}, I am ${age} years old!`;

undefined 与 null

在 JavaScript 中,undefined 和 null 是两个基本数据类型

在 TypeScript 中,它们各自的类型也是 undefined 和 null,也就意味着它们既是实际的值,也是自己的类型

1
2
let u: undefined = undefined;
let n: null = null;

Array

TypeScript 像 JavaScript 一样可以操作数组元素

  • 定义单一数据类型
1
2
3
4
5
// 1.在元素类型后面接上[]
const list1: number[] = [1, 2, 3];

// 2.使用数组泛型,Array<元素类型>
const list2: Array<number> = [1, 2, 3];
  • 定义多种数据类型
1
2
const list3: (string | number | boolean)[] = [123, true, "ts"];
const list4: Array<string | number | boolean> = [true, "ts", 456];

Tuple

元组类型允许表示一个已知元素数量类型的数组,各元素的类型不必相同

比如,可以定义一对值分别为 stringnumber 类型的元组。

1
2
3
let t1: [string, number];
t1 = ["hello", 10]; // OK
t1 = [10, "hello"]; // Error

当访问一个已知索引的元素,会得到正确的类型:

1
2
console.log(t1[0].substring(1)); // OK
console.log(t1[1].substring(1)); // Error, 'number' 不存在 'substring' 方法

元组和数组的区别

  • 首先,数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中)
  • 其次,元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型
1
2
3
4
5
const info: (string | number)[] = ["aaa", 18, 1.8];
const item1 = info[0]; // 不能确定类型

const tInfo: [string, number, number] = ["aaa", 18, 1.8];
const item2 = tInfo[0]; // 一定是string类型

应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
// 在函数中使用元组类型是最多的(函数的返回值)
function useState(initialState: number): [number, (newValue: number) => void] {
let stateValue = initialState;
function setValue(newValue: number) {
stateValue = newValue;
}

return [stateValue, setValue];
}

const [count, setCount] = useState(10);
console.log(count);
setCount(100);

enum

enum 类型是对 JavaScript 标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字

1
2
3
4
5
6
7
8
9
10
enum Color {
Red,
Green,
Blue
}

// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
const myColor: Color = Color.Green; // 0
console.log(myColor, Color.Red, Color.Blue);

默认情况下,从 0 开始为元素编号。 也可以手动的指定成员的数值。 例如,将上面的例子改成从 1 开始编号:

1
2
3
4
5
6
enum Color {
Red = 1,
Green,
Blue
}
const c: Color = Color.Green;

或者,全部都采用手动赋值:

1
2
3
4
5
6
enum Color {
Red = 1,
Green = 2,
Blue = 4
}
const lor = Color.Green;

枚举类型可以由枚举的值得到它的名字。 例如,知道数值为 2,但是不确定它映射到 Color 里的哪个名字,可以查找相应的名字

1
2
3
4
5
6
7
8
enum Color {
Red = 1,
Green,
Blue
}
const colorName: string = Color[2];

console.log(colorName); // 'Green'

使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 定义枚举类型
enum Direction {
LEFT,
RIGHT
}

const d1: Direction = Direction.LEFT;

function turnDirection(direction: Direction) {
switch (direction) {
case Direction.LEFT:
console.log("角色向左移动一个格子");
break;
case Direction.RIGHT:
console.log("角色向右移动一个格子");
break;
}
}

// 监听键盘的点击
turnDirection(Direction.LEFT);

any

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any 类型来标记这些变量:

1
2
3
let notSure: any = 4;
notSure = "maybe a string";
notSure = false; // 也可以是个 boolean

在对现有代码进行改写的时候,any 类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。并且当你只知道一部分数据的类型时,any 类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:

1
2
3
const list: any[] = [1, true, "free"];

list[1] = 100;

void

某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

  • 在 TS 中如果一个函数没有任何的返回值, 那么返回值的类型就是 void 类型
  • 如果返回值是void类型, 那么我们也可以返回undefined(TS 编译器允许这样做而已), null不可以
1
2
3
4
5
6
function fn(): void {
console.log("fn()");
// return undefined
// return null // error
// return 1 // error
}

声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined

1
let a: void = undefined;

Object

object 表示非原始类型,也就是除 numberstringboolean之外的类型。

使用 object 类型,就可以更好的表示像 Object.create 这样的 API。例如:

1
2
3
4
5
6
7
8
9
function fn2(obj: object): object {
console.log("fn2()", obj);
return {};
// return undefined
// return null
}
console.log(fn2(new String("abc")));
// console.log(fn2('abc') // error
console.log(fn2(String));

Symbol

在 ES5 中,是不可以在对象中添加相同的属性名称的,比如下面的做法:

1
2
3
4
const person = {
identity: "aaa",
identity: "bbb" // error
};

通常的做法是定义两个不同的属性名字:比如 identity1 和 identity2

但是也可以通过 symbol 来定义相同的名称,因为 Symbol 函数返回的是不同的值

1
2
3
4
5
6
7
const s1: symbol = Symbol("title");
const s2: symbol = Symbol("title");

const person = {
[s1]: "aaa",
[s2]: "bbb"
};

unknown

unknown 类型默认情况下在上面进行任意的操作都是非法的
要求必须进行类型的校验(缩小), 才能根据缩小之后的类型, 进行对应的操作

1
2
3
4
5
6
7
let foo: unknown = "aaa";
foo = 123; // error

if (typeof foo === "string") {
// 类型缩小
console.log(foo.length, foo.split(" "));
}

never

  • never 表示永远不会发生值的类型,比如一个函数
  • 如果一个函数中是一个死循环或者抛出一个异常,那么这个函数不会返回东西,那么写void类型或者其他类型作为返回值类型都不合适,就可以使用never类型
  • 实际开发中只有进行类型推导时, 可能会自动推导出来是never类型, 但是很少使用它
1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.一个函数是死循环
function foo(): never {
while (true) {
console.log("-----");
}
throw new Error("123");
}
foo();

// 2.解析歌词的工具,返回值是 never[]
function parseLyric() {
return [];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 2. 封装框架/工具库的时候可以使用一下never
// 其他时候在扩展工具的时候, 对于一些没有处理的case, 可以直接报错
function handleMessage(message: string | number | boolean) {
switch (typeof message) {
case "string":
console.log(message.length);
break;
case "number":
console.log(message);
break;
case "boolean":
console.log(Number(message));
break;
default:
const check: never = message;
}
}

handleMessage("aaaa");
handleMessage(1234);
handleMessage(true);
handleMessage({ name: "aaa" }); // message 赋值给 check,为never类型