TypeScript 中你不一定知道的 top types,在用 any 之前先试试 unknown?

简介: 最近发现了一本 TS 相关的电子书,Tackling TypeScript[1]。随便翻看了一下,就发现了自己很感兴趣的一个问题,并且也经常听说在国内面试中出现。

来源


最近发现了一本 TS 相关的电子书,Tackling TypeScript[1]。随便翻看了一下,就发现了自己很感兴趣的一个问题,并且也经常听说在国内面试中出现。

加上国内的相关资料确实不多,花了点时间翻译了下这一章节。

英文基础好的同学可以直接去电子书地址阅读,如果觉得有帮助的话,可以买下这本书,或者捐助作者。

输入图片说明


前言


在 TypeScript 中, 和 是包含了所有值的类型。anyunknown

本文会详细介绍它们是什么,用在哪儿。


TS 中的两个 顶级类型


any和 是 TypeScript 中欧所谓的 ,详见 Wikipedia[2]unknowntop 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 静态类型系统提供的所有保护。

更好的选择是:

  1. 使用更具体的类型
  2. 使用 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

相关文章
|
JavaScript 开发者 索引
搞懂 TypeScript 中的映射类型(Mapped Types)
搞懂 TypeScript 中的映射类型(Mapped Types)
755 0
|
2月前
|
JavaScript
typeScript基础(2)_any任意值类型和类型推论
本文介绍了TypeScript中的`any`任意值类型,它可以赋值为其他任何类型。同时,文章还解释了TypeScript中的类型推论机制,即在没有明确指定类型时,TypeScript如何根据变量的初始赋值来推断其类型。如果变量初始化时未指定类型,将被推断为`any`类型,从而允许赋予任何类型的值。
56 4
|
5月前
|
JavaScript 安全
8.【TypeScript 教程】Never 与 Unknown
8.【TypeScript 教程】Never 与 Unknown
37 3
|
6月前
|
JavaScript 前端开发
TypeScript内置类型一览(Record<string,any>等等)(下)
TypeScript内置类型一览(Record<string,any>等等)
|
5月前
|
JavaScript
typescript Any
typescript Any
|
6月前
|
JavaScript
TypeScript内置类型一览(Record<string,any>等等)(中)
TypeScript内置类型一览(Record<string,any>等等)
|
6月前
|
JavaScript
TypeScript内置类型一览(Record<string,any>等等)(上)
TypeScript内置类型一览(Record<string,any>等等)
124 0
|
6月前
|
JavaScript 安全
TypeScript中any unkown never的区别
TypeScript中any unkown never的区别
|
JavaScript 前端开发 测试技术
TypeScript高级类型:探索Mapped Types的威力及衍生
TypeScript高级类型:探索Mapped Types的威力及衍生
「TypeScript」你必须要知道的 TS 高级技能点 —— Utility Types
「TypeScript」你必须要知道的 TS 高级技能点 —— Utility Types