这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战
新增的扩展类型
TS 作为 JS 的超集,除了支持 JS 的类型之外,还提供了一些额外的扩展类型,比如说,元组,枚举等,这些扩展类型的加入丰富了 TS的数据类型,利用好这些扩展类型,我们就可以提高代码的易读性,以及健壮性。
听起来是不是很酷,下面我们就来学习一下 TS 的扩展类型吧
资料-特殊的函数返回值
never
为 TypeScript 增加 never 类型: github.com/Microsoft/T…
在上述的链接中,作者为 TypeScript 新增了 never 类型。其有两种具体场景:
- 作为不会返回( return )的函数的返回值类型
- never 是类型保护机制下,永远不会发生改变的变量类型
作为不会返回( return )的函数的返回值类型
以下是作者给出的示例代码,在以下场景中,函数的返回值是 never。
// 返回never的函数 必须存在 无法达到( unreachable ) 的终点
function error(message: string): never {
throw new Error(message);
}
// 由类型推论得到返回值为 never
function fail() {
return error("Something failed");
}
// 返回never的函数 必须存在 无法达到( unreachable ) 的终点
function infiniteLoop(): never {
while (true) {
}
}
never 是类型保护机制下,永远不会被观察到( observed )的变量类型
在 TS 中, null 和 undefined 是任何类型的有效值,所以无法正确地检测它们是否被错误地使用。于是 TS 引入了 --strictNullChecks
这一种检查模式。
由于引入了 --strictNullChecks
,在这一模式下,null 和 undefined 能被检测到。所以 TS 需要一种新的底部类型( bottom type )。所以就引入了 never。
「never 是类型保护机制下,永远不会发生改变的变量类型」,这一说法看起来比较绕,因为这不符合我们日常的编程习惯,还是用代码来解释,我们看以下代码:
// Compiled with --strictNullChecks
function fn(x: number | string) {
if (typeof x === 'number') {
// x: number 类型
} else if (typeof x === 'string') {
// x: string 类型
} else {
// x: never 类型
// --strictNullChecks 模式下,这里的代码将不会被执行,x 无法被观察
}
}
void
void 表示没有任何类型。 当一个函数没有返回值时,TS 会认为它的返回值是 void 类型。例如:
function foo(): void {
alert('foo');
}
当我们声明一个变量类型是 void 的时候,它仅可以被赋值为 null 和 undefined;
let unusable: void = undefined;
never 和 void 的区别
- void 可以被赋值为 null 和 undefined的类型。 never 则是一个不包含值的类型。
- 拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常。
字符串、数字、布尔值字面量
接下来,我们学习字面量,字面量包含字符串、数字、布尔值字面量。
我们先来看看之前见过的报错信息
let seven: number = 7;
seven = 'Seven'; // 报错,不能将类型“Seven”分配给类型“number”
// 为什么这里写的是类型“Seven”呢?这个东西,不应该是 string 类型吗?其实这个 “Seven” 就是字符串字面量类型。
字符串字面量
一般我们会使用联合类型定义多个字符串字面量。
type FavoriteNumber = 'One' | 'Two' | 'Seven';
let seven: FavoriteNumber = 'Seven';
// 如果是上面三者不存在的,就会报错,不能将类型“Six”分配给类型“FavoriteNumber”
// 同时,我们在使用的时候,也会有代码提示我们只能选择这三者中某一者。
let seven: FavoriteNumber = 'Six';
数字字面量,跟字符串字面量类似,可以直接使用数字来约束,number 必须是 1,2,7中的某一个,如果不是的话,肯定会报错。
type FavoriteNumber = 1 | 2 | 7;
let seven: FavoriteNumber = 7;
同时数字字面量和字符串字面量,是可以使用联合类型混用的。
这样的话,seven 要么是这个字符串,要么是这个数字。
type FavoriteNumber = 1 | 'Seven';
let seven: FavoriteNumber = 'Seven';
布尔值字面量
type FavoriteNumber = 1 | 'Seven' | true;
let seven: FavoriteNumber = false;
字符串字面量 vs 联合类型
我们先来看一下二者的定义
字符串字面量
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {};
handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'
// error TS2345: Argument of type '"dbclick"' is not assignable to parameter of type 'EventNames'.
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
myFavoriteNumber = true;
// error TS2322: Type 'boolean' is not assignable to type 'string | number'.
二者的区别
理解二者的定义后,我们就能比较直观地看出二者的区别了。
- 字符串字面量 限定了使用该字面量的地方仅接受特定的值
- 联合类型 对于值并没有限定,仅仅限定值的类型需要保持一致