持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
2. 类型断言
2.1 概念
Typescript 可以根据规则推断变量的类型,然而它也允许覆盖已有的推断,按照自定义的方式设置变量的类型,这就是类型断言。
在下面的代码中,如果直接将 foo 设置为空对象,则在给属性赋值的时候就会报错。这时候可以通过 as实现类型断言避免报错。
const foo = {};
foo.bar = 23; // error TS2339: Property 'bar' does not exist on type '{}'.
foo.bars = "45"; // error TS2339: Property 'bars' does not exist on type '{}'.
interface Foo {
bar: number;
bars: string;
}
const foo = {} as Foo;
foo.bar = 23;
foo.bars = "45";
2.2 as Foo 和 <Foo>
类型断言最早是使用<Foo>的形式,但这样容易和 JSX 语法产生混淆,所以提倡使用 as 的形式进行类型断言。
let foo: any;
let bar = <string>foo;
2.3 类型断言和类型转换
类型转换是运行时的语法支持,而类型断言时编译时的类型判断,它们是不同的两个概念。
2.4 类型断言被认为是有害的
使用类型断言更有利于进行旧项目的代码迁移,但是不合理使用类型断言也会存在问题。
在下面的代码中,使用类型断言但后续的代码没有添加对应的属性,编译的时候不会报错。而只有书写成这种形式const foo: Foo = {},不添加对应属性编译的时候才会报错。
interface Foo {
bar: number;
bars: string;
}
const foo = {} as Foo; // 正常
interface Foo {
bar: number;
bars: string;
}
const foo: Foo = {}; // error TS2739: Type '{}' is missing the following properties from type 'Foo': bar, bars
2.5 双重断言
尽管前面已经介绍了类型断言不安全,但还是有些场合适合使用它。
- 通过类型断言可以给参数增加更具体的类型判断
function handler(event: Event) {
const mouseEvent = event as MouseEvent;
}
- 将一种类型的变量断言为另一种类型会报错,但是可以通过先判断为 any 类型,再判断为另一种类型,这样不会报错。
function handler(event: Event) {
const element = event as HTMLElement; // Error: 'Event' 和 'HTMLElement' 中的任何一个都不能赋值给另外一个
}
function handler(event: Event) {
const element = (event as any) as HTMLElement; // ok
}
2.6 小结
Typescript 会根据规则推断变量的类型,但是可以通过类型断言的方式覆盖自动推断的结果。在书写形式上,为了避免和 JSX 语法混淆,提倡使用 as 的形式而不是尖括号的形式。
另外,类型断言不同于类型转换,前者是编译时执行的语法,后者是运行时执行的操作。
类型断言是不安全的,但是有两种场景适合使用类型断言:一是进一步判断变量的具体类型,二是通过双重断言将一种类型的变量判断为另一种类型的变量