类型系统是 typescript 最吸引人的特性之一,但它的强大也让我们又爱又恨,每个前端同学在刚从 javascript 切换到 typescript 时都会有一段手足无措的时光,为了不让编译器报错恨不得把所有变量都标注成 any 类型,而后在不断地填坑中流下悔恨的泪水。
谨以此文记录我在学习 typescript 类型系统使用方法的过程中遇到的一些问题,以供大家参考,避免大脑进水。
(本文默认所有读者熟知活动所有 ES6 语法及特性)
Change Log
2018-11-14
改正了枚举与 .d.ts 文件的说明
2018-11-13
修正了 .d.ts 一节中 class 在 .d.ts 文件中定义时使用了 export default 语法的问题
增加了 .d.ts 文件的使用注意事项
增加了枚举(enum)不能定义在 .d.ts 文件中的说明
增加了枚举(enum)部分对于为什么要使用 type xxx = 'a' | 'b' 来替换枚举进行了说明
0x00 无知
类型声明
基础类型
直接将类型附在变量声明之后,并以冒号分隔。
const count: number = 3;
const name: string = 'apples';
const appleCounts: string = count + name;
assert.strictEqual(appleCounts, '3apples');
引用类型
稍微复杂一点的,如数组 & 对象,按照其内成员结构进行声明。
const object: { a: number } = { a: 1, };
const array1: number[] = [1,];
const array2: Array = [2,];
函数类型
写法极像箭头函数。
const someFn: (str: string) => number = function (str: string) {
return +str;
}
typescript 扩展的辅助类型
any
啥都能放,但并不建议大量使用,如果所有变量都是 any,那 typescript 跟 javascript 又有什么区别呢。
const variable: any = '5';
void
空类型,一般用来表示函数没有返回值。
function someFn (): void {
1 + 1;
}
类型并联
当一个变量可能是多种类型时,使用 | 进行多个不同类型的分隔:
const nos: number | string = '1';
在引用类型中使用
错误用法
一定,一定,一定 不要用 , 作分隔符。
const object: { a: [number, string] } = { a: 1, };
正确用法
const object: { a: number | string } = { a: 1, };
const array1: (number | string)[] = [ 1, ];
const array2: Array = [ 2, ];
或
type numberOstring = number | string;
const object: { a: numberOstring } = { a: 'yes', };
const array1: numberOstring[] = [ 'yes', ];
const array2: Array = [ 'yes', ];
在函数入参 & 出参中声明类型
函数的入参类型跟声明变量的类型时差不多,直接在变量名后跟类型名称就可以了。
返回值的类型则跟在参数的括号后面,冒号后面跟一个返回值的类型。
function someFn (arg1: string, arg2: number): boolean {
return +arg1 > arg2;
}
箭头函数
参数与返回值的声明方法与普通函数无二。
setTimeout((): void => {
console.log('six six six');
}, 50);
在类中声明类型
实例属性记得一定要初始化。
class SomeClass {
a: number = 1;
b: string;
static a: boolean;
constructor () {
this.b = 'str';
}
method (str: string): number {
return +str;
}
}
类型转换
当你在声明一个普通的对象(其他类型也有可能,此处仅使用对象作为例子)时,typescript 并不会自动为你添加上对应的类型,这会造成你在赋值时触发 TS2322: Type 'xxx' is not assignable to type 'xxx'. 错误,此时就需要使用显式类型转换来将两边的类型差异抹平。
类型转换的前提是当前类型是真的可以转换为目标类型的,任何必选属性的缺失,或是根本无法转换的类型都是不允许的。
尖括号转换
并不推荐这种方法,因为有时编辑器会把它当成 jsx 处理,产生不必要的 warning。
const object1: object = {
a: 1,
};
const object2: { a: number } = object1;
as 表达式转换
const object1: object = {
a: 1,
};
const object2: { a: number } = object1 as { a: number };
0x01 理智
自定义类型
相当于联结多个不同类型,并为他们创造一个假名,平时写多个类型并联实在是太累了的时候可以试试这个方法。
它的值可以是类型,也可以是具体的变量值。
type NumberOrString = number | string;
type Direction = 'Up' | 'Right' | 'Down' | 'Left';
const num: NumberOrString = 1;
const dir: Direction = 'Up';
枚举
官方
注意:枚举内部赋值时如果为数字,可以只赋值第一个,后面几个会随之递增,如果为字符串,则需要全部赋值,否则就会报错。
enum Direction {
Up = 1,
Right,
Down,
Left
}
const dir: Direction = Direction.Up;
我的方法
如果你的代码中准备使用 enum 作为右值,那请不要把 enum 声明在 .d.ts 文件中,这是因为 ts 在编译的时候