:::info 💡 根据 遗忘曲线:如果没有记录和回顾,6天后便会忘记75%的内容

  1. 读书笔记正是帮助你记录和回顾的工具,不必拘泥于形式,其核心是:记录、翻看、思考

:::

keyof 类型操作符

keyof是索引类型查询的语法,会返回该对象属性名组成的一个字符串字面量或者数字字面量的联合。

  1. interface foo {
  2. a: number
  3. b: string
  4. }
  5. type A = keyof foo // "a" | "b"

有点类似Object.keys()

同泛型(Generics)的结合使用

  1. function pickSingleValue<T extends object, U extends keyof T>(
  2. obj: T,
  3. key: U
  4. ): T[U] {
  5. return obj[key]
  6. }

<font style="color:rgb(63, 63, 63);">T extends object</font> 理解为T被限制为对象类型

<font style="color:rgb(63, 63, 63);">U extends keyof T</font> 理解为泛型 U 必然是泛型 T 的键名组成的联合类型

索引签名Index Signature

索引签名用于快速建立一个内部字段类型相同的接口,如

  1. interface Foo {
  2. [key: string]: string
  3. }
  4. // 等同于Record<string, string>

接口Foo被认定字段全部为string类型,需要注意⚠️的是JS的对象可以同时通过字符串/数字访问队形属性,因此keyof Foo结果会有string | number

索引类型 & 映射类型 - 图1

映射类型 Mapped Types

映射类型同样是类型编程的重要底层组成,通常用于在旧有类型的基础上进行改造,包括接口包含字段、字段的类型、修饰符等等。
  1. interface Obj {
  2. a: boolean
  3. b: string
  4. c: number
  5. d: () => void
  6. }
现在我们像实现一个接口,它的字段和接口A完全相同,但其中属性值类型为string。 如果把接口换做对象,我们的思路是拷贝一下独享,new一个新对象,然后遍历原先对象的键值对来填充新对象,对应接口其实也一样
  1. type Stringify<T> = {
  2. [k in keyof T]: string
  3. }
使用如下

索引类型 & 映射类型 - 图2


这种思路,其实也是一般工具类型的底层实现了

  1. // Clone
  2. type Clone<T> = {
  3. [k in keyof T]: T[k]
  4. }
  5. // Partial: 接口下的字段全部变为可选的
  6. type Partial<T> = {
  7. [k in keyof T]?: T[k]
  8. }