TypeScript 断言
1. 类型断言
有时候会遇到这样的情况,开发者比 TypeScript 更了解某个值的详细信息。通常这会发生在开发者清楚地知道一个实体具有比它现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。类型断言好比其他语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在编译阶段起作用。
类型断言有两种形式:
1.“尖括号” 语法
1
2
3let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length;
2. as 语法
1
2
3let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;
以上两种方式虽然没有任何区别,但是尖括号格式会与 react 中 JSX 产生语法冲突,因此我们更推荐使用 as 语法。
2. 非空断言
在上下文中,当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。具体而言,x! 将从 x 值域中排除 null 和 undefined 。
那么非空断言操作符到底有什么用呢?下面是非空断言操作符的一些使用场景。
1. 忽略 undefined 和 null 类型
1
2
3
4
5
6
7function myFunc(maybeString: string | undefined | null) { // Type 'string | null | undefined' is not assignable to type 'string'. // Type 'undefined' is not assignable to type 'string'. const onlyString: string = maybeString; // Error const ignoreUndefinedAndNull: string = maybeString!; // Ok }
2. 调用函数时忽略 undefined 类型
1
2
3
4
5
6
7
8type NumGenerator = () => number; function myFunc(numGenerator: NumGenerator | undefined) { // Object is possibly 'undefined'.(2532) // Cannot invoke an object which is possibly 'undefined'.(2722) const num1 = numGenerator(); // Error const num2 = numGenerator!(); //OK }
因为 ! 非空断言操作符会从编译生成的 JavaScript 代码中移除,所以在实际使用的过程中,要特别注意。比如下面这个例子:
1
2
3
4const a: number | undefined = undefined; const b: number = a!; console.log(b);
以上 TS 代码会编译生成以下 ES5 代码:
1
2
3
4
5"use strict"; const a = undefined; const b = a; console.log(b);
虽然在 TS 代码中,我们使用了非空断言,使得 const b: number = a!; 语句可以通过 TypeScript 类型检查器的检查。但在生成的 ES5 代码中,! 非空断言操作符被移除了,所以在浏览器中执行以上代码,在控制台会输出 undefined。
3. 确定赋值断言
在 TypeScript 2.7 版本中引入了确定赋值断言,即允许在实例属性和变量声明后面放置一个 ! 号,从而告诉 TypeScript 该属性会被明确地赋值。为了更好地理解它的作用,我们来看个具体的例子:
1
2
3
4
5
6
7
8let x: number; initialize(); // Variable 'x' is used before being assigned.(2454) console.log(2 * x); // Error function initialize() { x = 10; }
很明显该异常信息是说变量 x 在赋值前被使用了,要解决该问题,我们可以使用确定赋值断言:
1
2
3
4
5
6
7let x!: number; initialize(); console.log(2 * x); // Ok function initialize() { x = 10; }
通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。
TypeScript 类型守卫
类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。
换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。目前主要有四种的方式来实现类型保护:
4.1 in 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19interface Admin { name: string; privileges: string[]; } interface Employee { name: string; startDate: Date; } type UnknownEmployee = Employee | Admin; function printEmployeeInformation(emp: UnknownEmployee) { console.log("Name: " + emp.name); if ("privileges" in emp) { console.log("Privileges: " + emp.privileges); } if ("startDate" in emp) { console.log("Start Date: " + emp.startDate); } }
4.2 typeof 关键字
1
2
3
4
5
6
7
8
9
10function padLeft(value: string, padding: string | number) { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value; } if (typeof padding === "string") { return padding + value; } throw new Error(`Expected string or number, got '${padding}'.`); }
typeof 类型保护只支持两种形式:typeof v === “typename” 和 typeof v !== typename,“typename” 必须是 “number”, “string”, “boolean” 或 “symbol”。 但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。
4.3 instanceof 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20interface Padder { getPaddingString(): string; } class SpaceRepeatingPadder implements Padder { constructor(private numSpaces: number) {} getPaddingString() { return Array(this.numSpaces + 1).join(" "); } } class StringPadder implements Padder { constructor(private value: string) {} getPaddingString() { return this.value; } } let padder: Padder = new SpaceRepeatingPadder(6); if (padder instanceof SpaceRepeatingPadder) { // padder的类型收窄为 'SpaceRepeatingPadder' }
4.4 自定义类型保护的类型谓词
通过 type is xxx 这样的类型谓词来进行类型保护
1
2
3
4
5
6
7function isNumber(x: any): x is number { return typeof x === "number"; } function isString(x: any): x is string { return typeof x === "string"; }
最后
以上就是专一大树最近收集整理的关于TypeScript 类型断言和类型守卫TypeScript 断言TypeScript 类型守卫的全部内容,更多相关TypeScript内容请搜索靠谱客的其他文章。
发表评论 取消回复