《Effective TypeScript 》-- 条款8: 知道如何分辨符号是类型空间还是值空间

234 阅读4分钟

条款8: 知道如何分辨符号是类型空间还是值空间

这里的符号,指的是变量符号。

TypeScript 中的一个符号必然是以下空间的一个:值空间或者类型空间;

理解一下以上的概念:

  • 值空间,就是存储在运行时内存中数据;
  • 类型空间,我们可以理解为,他只是在静态检查时存在,运行时会被擦除
  • 一个变量名,可以同时存在于值空间和类型空间;

所以一个关键的点是,我们需要根据上下文的场景去推断一个变量符号是处于值空间还是类型空间,虽然很多时候我们会通过对类型空间的值进行命名上的约定来识别(如interface 定义的值以 I 开头,type 定义的值以 T 开头),但是这并不能解决所有的问题,需要通过上下文来推断。

TypeScript 中的关键字

识别类型的关键词

  • :冒号可以指定变量的类型;
  • as 类型断言

类型定义的关键词

  • type 类型别名,给类型起一个新的名字,可以作用于原始值、联合类型、元组以及其他任何需要手写的类型

    • 类型别名不会新建一个类型,他起了一个新的名字引用了已存在的类型;
    • 给基本类型起别名,图 type T1 = 1000; 基本上用途不大;
    • 类型别名通常是用在联合类型;
    • type 和 interface 的区别后续单独描述;
  • interface 我们可以用interface 来定义一个复杂类型;

  • enum 该关键词可以用来定义枚举类型,他同时会生成一个 JS 的变量,可以在运行时使用;

  • class 关键词,他同时生成了一个构造函数和一个类型;

类型操作的关键词

  1. typeof TS 和 JS 同时存在,作用是转换 JS data ,即转换一个 JS 的数据,而不是转换一个类型,因为运行时类型被擦除后,typeof "类型" 就会报错;

    • 定义一个值变量时,使用 typeof,如 const a = typeof xxx; 返回的是一个字符串,该字符串标识 xxx 在内存中存储的形式,有 string nunber boolean object undefined null 六种形式
    • 定义一个类型时,使用 typeof,如 type T1 = typeof xxx; 即返回的是 xxx 的类型定义,返回的是类型,会被构建时会被擦除掉;
  2. keyof TS 中存在,JS中不存在,作用是获取一个复杂类型的所有的key值作为一个联合类型;

    • keyof 基本类型的type,没有意义;如 type T1 = '123'; type T2 = keyof T1;返回的是所有字符串包装对象的所有的 key
  3. in 用来遍历枚举类型,联合类型也是枚举类型;

// TS 联合类型 type TsTypeUnion = "first" | "second"; 

// type TsTypeObject1 = { first: any, second: any };
type TsTypeObject1 = {
    [P in TsTypeUnion]: any;
};

// type TsTypeObject2 = { first: "first", second: "second" }
type TsTypeObject2 = {
    [P in TsTypeUnion]: P;
};

  • in + keyof 关键字

    • in => 遍历枚举类型
    • keyof => 将复杂对象的类型的key变成一个联合类型;
    // TS 描述对象的类型
    type TsTypeObject = { first: string; second: number; };
    // type TsTypeObjectNew1 = { first: any, second: any }
    type TsTypeObjectNew1 = { [P in keyof TsTypeObject]: any; };
    
  • in + typeof + keyof关键词

    • typeof 将JS对象 => 描述该对象的类型
    • keyof => 获取描述对象类型所有的key,组成联合类型
    • in 遍历枚举类型
    // JS 对象
    const JsObject = { name: "张大炮", age: 18, }; 
    // type TsTypeObject1 = { name: any; age: any; } 
    type TsTypeObject1 = { [P in keyof typeof JsObject]: any; };
    
  1. extends

在 TS 中,extends 大体分为三种使用场景:

  • 类型继承,约束 A 去继承类型 B(interface 可以使用继承,type 不支持)
  • 定义泛型,T extnds objet
    type TOnlyWantNumber<T> = T extends number ? any : never;
    
  1. as

AS 运算符的作用是类型断言,改变原有的类型定义,分为以下两个场景:

  • 断言;
  • 转换;
  1. []属性访问器

JS 中 a.b 和 a['b']是等价的,但是在 TS 中获取类型只能使用 a['b']的方式

TS 和 JS 中其他的一些不同的意义

  1. this 关键字

值空间中的this 是 JS 的this关键字;作为一个类型 this 是this的TS类型;

  1. &、| 符号

在值空间中,& 和 | 符号是位上的 AND和OR;在值空间中,他们交集和联合运算符;

  1. Const 在 JS 中是引入一个新的变量,但是 as const 改变了一个蚊子或者蚊子表达式的推断类型;

  2. 结构赋值

在JS中可以通过解构赋值来为对象中的每个属性创建局部变量,但是TS需要将类型和值分类;

后记:

本条款的含义在意,我们在写 TS 代码时,要知道一个变量是属于类型空间还是值空间;一般我们可能需要通过上下文来进行判断变量符号,当熟练使用之后,我们可以通过一些关键词来迅速判断。但是如果有多种含义的关键词出现时,我们就需要更加谨慎的去判断。

参考学习文档

juejin.cn/post/703403…