what is 类型断言(Type Assertions)?

TS 支持用户以自己认可的方式去使用类型系统。TypeScript 类型断言用来告诉编译器你比它更了解这个类型,并且它不应该再发出错误。

类型断言的两种写法:

  • <类型>值/对象 <string>a

  • 值/对象 as 类型

一般用在不知道确切的类型的情况,但是我又可以笃定这个类型,站在使用者的角度,断言为确定的类型。从而可以使用相应的属性或方法。

类型断言的用途

常用在联合类型中,确定使用类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
function getLength(a: string | number): number {
//if ((a as string).length) {
if (<boolean>a) return 0; // 类型 "string | number" 到类型 "boolean" 的转换可能是错误的,因为两种类型不能充分重叠。如果这是有意的,请先将表达式转换为 "unknown"。
类型“number”不可与类型“boolean”进行比较。
if ((<string>a).length) {
return (<string>a).length;
} else {
return a.toString().length;
}
}
console.log(getLength(6)); //1
console.log(getLength("hello")); //5
getLength(false);

如果要断言为一种未知的类型时(即不可推断的类型),如上边的例子,我断言为Boolean ,这时会报错。代码提示为如果要转化为boolean,那么需要先转为unknown。

将一个父类断言为更加具体的子类

Todo

将任何一个类型断言为 any

Any (任意)支持任意类型,一般可理解为 全集。

1
type any = string | number | boolean | array | object | symbol | ...

所以,当使用any 时,不能做任何方式的类型推断

但我们可以将一个不太确定的类型断言成 any (这是一个取巧的办法,一般不建议)。

1
2
3
4
5
6
// 常见案例是:

window.foo = 1; // error
// ^__ 类型“Window & typeof globalThis”上不存在属性“foo”。ts(2339)

(window as any).foo = 1; // ok
将 any 断言为一个具体的类型

any 可以 断言为一个常规类型。

any 会是一个常见的现象,比如以来的第三方库,就是any。但当我们确认它的类型之后,可以做类型断言,这种断言是一次类型收窄,方便了后续的操作,可以使用类型推断

1
2
3
4
5
6
window.foo = 1; // OK
// global.d.ts
declare interface Window {
foo: number;
$: JQuery;
}

as const

TODO

断言的逻辑

断言不是任意断言,而是有规律,有预期的断言。

结构化

​ TODO

双重断言

双重断言可以对任意一种类型进行断言而不按照其逻辑。

例如

1
2
3
let a = '3';

(a as unknown as number).toFixed(2);

可以将一个string,断言成 number。

当然这是有无意义还需要用户自己判断。

在JSX/TSX 中的注意点

由于jsx 的语法原因,所以在编译改类型时,不能使用 <> 的语法去断言,ts 会提示语法错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { ReactElement } from "react";
type Props = {
children?: ReactElement;
a: string | number;
};
const Wrapper = (props: Props): ReactElement => {
const { a } = props;
(a as number).toFixed();
// (<number>a).toFixed();
return <span>{props.children}</span>;
};

export default Wrapper;

类型断言被认为是有害的