来源
最近发现了一本 TS 相关的电子书,Tackling TypeScript[1]。随便翻看了一下,就发现了自己很感兴趣的一个问题,并且也经常听说在国内面试中出现。
加上国内的相关资料确实不多,花了点时间翻译了下这一章节。
英文基础好的同学可以直接去电子书地址阅读,如果觉得有帮助的话,可以买下这本书,或者捐助作者。
输入图片说明
前言
在 TypeScript 中, 和 是包含了所有值的类型。any
unknown
本文会详细介绍它们是什么,用在哪儿。
TS 中的两个 顶级类型
any
和 是 TypeScript 中欧所谓的 ,详见 Wikipedia[2]:unknown
top types
顶级类型[...]是通用类型,有时称为通用超类型,因为任何给定类型系统中的所有其他类型都是子类型[...]。在大多数情况下,它是包含感兴趣的类型系统中所有可能的 [值] 的类型。
简单翻译过来就是说, 又称作通用父类型,基本上涵盖了类型系统中所有可能的值。top type
输入图片说明
顶部类型any
如果一个值是 any 类型,几乎对它做任何操作都没问题。
function func(value: any) { // 可以做数字操作 5 * value; // 可以假设一定有 propName 属性 value.propName; // 可以假设数字索引存在 value[123]; }
每种类型都可赋值给any类型:
let storageLocation: any; storageLocation = null; storageLocation = true; storageLocation = {};
any类型也可赋值给任何类型:
function func(value: any) { const a: null = value; const b: boolean = value; const c: object = value; }
一旦用了 any,我们就失去了 TypeScript 静态类型系统提供的所有保护。
更好的选择是:
- 使用更具体的类型
- 使用 unknown
总而言之,使用 any 是最下策。
例子:JSON.parse()
JSON.parse()
的结果根据输入而动态的改变,所以只能用 any 类型(我从类型签名中移除了参数 )reviver
JSON.parse(text: string): any;
JSON.parse()
是在 unknown 类型出现之前被添加到 TypeScript 系统中的,否则它的返回类型应该是 unknown。
例子:String()
函数 可以将任意类型的值转为字符串,所以具有以下类型签名:String()
interface StringConstructor { (value?: any): string; // ··· }
Top type unknown
unknown 类型是安全版本的 any,每当你想用 any 的时候,先试试用 unknown。
any 允许你做几乎所有操作,unknown 的限制性则更多。
当我们对 unknown 类型的值做任何操作之前,我们必须先这样缩窄它的类型:
- Type assertions[3]:
function func(value: unknown) { // @ts-expect-error: Object is of type 'unknown'. value.toFixed(2); // Type assertion: (value as number).toFixed(2); // OK }
- Equality:
function func(value: unknown) { // @ts-expect-error: // Object is of type 'unknown'. value * 5; if (value === 123) { // equality // 推断出类型: 123 value; value * 5; // OK } }
- Type guards[4]:
function func(value: unknown) { // @ts-expect-error: // Object is of type 'unknown'. value.length; // type guard if (typeof value === 'string') { // 推断出类型: string value; value.length; // OK } }
- Assertion functions[5]:
function func(value: unknown) { // @ts-expect-error: // Object is of type 'unknown'. value.test('abc'); assertIsRegExp(value); // 推断出类型: RegExp value; value.test('abc'); // OK } /** An assertion function */ function assertIsRegExp(arg: unknown): asserts arg is RegExp { if (! (arg instanceof RegExp)) { throw new TypeError('Not a RegExp: ' + arg); } }
参考资料
[1]
处理打字稿:https://exploringjs.com/tackling-ts/ch_any-unknown.html#typescripts-two-top-types
[2]
维基百科: https://en.wikipedia.org/wiki/Top_type
[3]
类型断言:https://exploringjs.com/tackling-ts/ch_type-assertions.html
[4]
类型防护装置:https://exploringjs.com/tackling-ts/ch_type-guards-assertion-functions.html
[5]
断言函数:https://exploringjs.com/tackling-ts/ch_type-guards-assertion-functions.html