Appearance
原始类型与对象类型
null 和 undefined
null 与 undefined 在 typescript 中表示有具体意义的类型,这与 javaScript 中不同。
在未开启 strictNullChecks
的情况下,这两种类型会被视为其他类型的子类型,比如,string 类型会被认为包含 null 和 undefined 类型
void
void 用于描述一个内部没有 return 语句,或者没有显示 return 一个值的函数的返回值
function func1() {}
function func2() {
return;
}
function func3() {
return undefined;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
在这里,func1 与 func2 的返回值类型都会被隐式推导为 void,只有显式返回了 undefined 值的 func3 其返回值类型才被推导为了 undefined。但在实际的代码执行中,func1 与 func2 的返回值均是 undefined。
数组与元组
在处理大量数据时,数组是我们经常使用的类型。其在 Typescript 中声明方式如下:
const arr1:string[] = []; // 这种方式更常用
const arr2:Array<string> = [];
1
2
2
在数据大小未知的情况下,可以使用数组。但,对于定长的数据而言,元组可能更合适。
元组特点:
- 在下标越界时,可以给出明确的类型报错
- 可以精确标记索引位置上的元素类型
- 支持可选成员
- 对于隐式越界的情况,如通过结构赋值的形式,也可以给出警告
const arr3:[string, string, string] = ['lyx', 'lyx', 'lyx'];
console.log(arr1[15]); // 错误,在索引15处没有元素
1
2
2
// 支持不同类型的元素
const arr4:[string, number, boolean] = ['lyx', 12, boolean];
1
2
2
// 支持不同类型的元素
const arr5:[string, number?, boolean?] = ['lyx'];
1
2
2
对于标记为可选的成员,在 --strictNullCheckes 配置下会被视为一个 string | undefined 的类型。此时元组的长度属性也会发生变化,比如上面的元组 arr5 ,其长度的类型为 1 | 2 | 3:
在 Typescript 4.0 中,支持了具名元组,可以为元组中的元素打上类似属性的标记
const arr7: [name: string, age: number, male: boolean] = ['linbudu', 599, true];
1
具名元组不支持以 arr7[name]
的形式取的元素值
对象类型的类型标注
在描述对象类型时,常常使用 interface 来描述对象对外提供的接口
interface IDescription {
name:string;
age:number;
male:boolean;
}
const obj: IDescription = {
name: 'lyx',
age: 20,
male:true
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
注意:
- 每一个属性值必须与接口的属性类型一一对应
- 属性不能多或者少,不允许直接在对象内部声明,或是
obj.other = 'xxx' 这样的形式
属性修饰符: ? and readonly
?
:表示该属性是可选的
interface IDescription {
name: string;
age: number;
male?: boolean;
func?: Function;
}
const obj2: IDescription = {
name: 'linbudu',
age: 599,
male: true,
// 无需实现 func 也是合法的
};
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
在此时,即使你在 obj2
中定义了 male
属性,当时,访问 obj.male
时,其类型仍然会是 boolean | undefined
但是,可选属性不会影响你对属性赋值:
obj2.male = false;
obj2.func = () => {};
1
2
2
readonly
:表示该属性只读,不可以被再次赋值
数组与元组也有属性修饰符,但是:
- 数组/元组只能整体被标记为只读,而不能仅仅标记某个属性为只读
- 一旦被标记为只读,那这个只读数组/元组的类型上,将不再具有 push、pop 等方法(即会修改原数组的方法),因此报错信息也将是类型 xxx 上不存在属性“push”这种。这一实现的本质是只读数组与只读元组的类型实际上变成了 ReadonlyArray,而不再是 Array。
type 和 interface
type 和 interface 都可以用来描述对象、类的结构
推荐用法:
- interface 用来描述对象、类的结构
- type 用来将一个函数签名、一组联合类型、一个工具类型等等抽离成一个完整独立的类型
object、Object 和 {}
Object: 在 ts 中,Object 表现为包含所有的类型。这与 JS 中Object作为原型链的终点的含义不谋而合。
// 对于 undefined、null、void 0 ,需要关闭 strictNullChecks
const tmp1: Object = undefined;
const tmp2: Object = null;
const tmp3: Object = void 0;
const tmp4: Object = 'linbudu';
const tmp5: Object = 599;
const tmp6: Object = { name: 'linbudu' };
const tmp7: Object = () => {};
const tmp8: Object = [];
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
装箱类型(Boolean、String、Number、Symbol)与 Object 含义类似,它会包含 undefined、null、void 以及对应的拆箱类型
例如,String 类型会包含 undefined、null、void 以及 string 类型
在任何情况下,都不应该使用装箱类型
object 的引入就是为了解决对 Object 类型的错误使用,它代表所有非原始类型的类型,即数组、对象与函数类型
{}:可以认为是对象字面量类型,它意味着任何非 null / undefined 值
虽然其可以作为变量类型,但是无法对其进行任何赋值操作
总结:
在任何时候都不要,不要,不要使用 Object 以及类似的装箱类型。
当你不确定某个变量的具体类型,但能确定它不是原始类型,可以使用 object。但我更推荐进一步区分,也就是使用 Record<string, unknown> 或 Record<string, any> 表示对象,unknown[] 或 any[] 表示数组,(...args: any[]) => any表示函数这样。
我们同样要避免使用{}。{}意味着任何非 null / undefined 的值,从这个层面上看,使用它和使用 any 一样恶劣。