# TS关键字

一些进阶关键字,如果不懂只需要记住有这个东西就行。

keyof

keyof关键字可以获取某种类型的所有键,其返回类型是联合类型。

type A = keyof any // type A = string | number | symbol

type User = {
  name: string
  age: number
}
type Key = keyof User // type Key = number | string

// 直接获取对象中的所有类型
let obj = {
  name: 'xiaoming',
  age: 18
}
type Key = keyof typeof obj // type Key = number | string

搭配 in 遍历 keyof里联合类型获取key值

interface Data {
  name: string,
  age: number,
  sex: string
}
// 使用 key in 循环 Data接口,遍历成一个可选的类型别名
type Options<T extends object> = {
  [Key in keyof T]?:T[Key]
  // readonly [Key in keyof T]:T[Key] 或者
}

type C = Options<Data>
// type C = {
//   name?: string | undefined;
//   age?: number | undefined;
//   sex?: string | undefined;
// }

Partial

将某个类型里的属性全部变为可选项,只可以作为类型使用。

interface Data {
  name: string,
  age: number,
  sex: string
}
type A = Partial<Data>
// type A = {
//   name?: string | undefined;
//   age?: number | undefined;
//   sex?: string | undefined;
// }

type Person = {
  name: string,
  age: number,
  sex: boolean
}
type P = Partial<Person>
// type P = {
//   name?: string | undefined;
//   age?: number | undefined;
//   sex?: boolean | undefined;
// }

其原理就是利用 keyof in 循环替换一遍。

type Partial<T> = {
  [P in keyof T]?: T[P]
}

Readonly

将某个类型里的属性全部变为只读项。

type Person = {
  name: string,
  age: number,
  sex: boolean
}
type P = Readonly<Person>
// type P = {
//   readonly name: string;
//   readonly age: number;
//   readonly sex: string;
// }

实现原理

type Readonly<T> = {
  readonly [P in keyof T]?: T[P]
}

Pick 从某个类型里的属性取出几个想要的。

type Person = {
  name: string,
  age: number,
  sex: boolean
}
type P = Pick<Person, 'age' | 'name'>
// type P = {
//   age: number;
//   name: string;
// }

实现原理

type Pick<T, K extends keyof T> = {
	[key in K]: T[key]
}

Record 将传入的两个类型组装成新的类型,第一个可以是联合类型。

type Person = {
  name: string,
  age: number,
  sex: boolean
}

type K = 'A' | 'B' | 'C'
type R = Record<K, Person>

// 组装成新的类型
// type R = {
//   A: Person;
//   B: Person;
//   C: Person;
// }
let r:R = {
  A: {name: 'aaa', age: 18, sex: false},
  B: {name: 'bbb', age: 18, sex: false},
  C: {name: 'ccc', age: 18, sex: false}
}

// 联合keyof使用
type P = keyof Person
type R = Record<P, Person>
// 获取Person里所有的key
// type R = {
//   name: Person;
//   age: Person;
//   sex: Person;
// }
let p:R = {
  name: {name: 'aaa', age: 18, sex: false},
  age: {name: 'bbb', age: 18, sex: false},
  sex: {name: 'ccc', age: 18, sex: false}
}

实现原理

// string | number | symbol
type Record<K extends keyof any, T> = {
  [P in K]: T
}

从上面的关键字可以看出,通过泛型和keyof我们可以组装成我们想要的其他类型数据。

infer

infer作为extends的子语句使用,infer可以在extends的条件语句中推断待推断的类型。infer 后面定义一个名字,这个名字就代表剩下被推断的所有类型。

// 推断数组中的某些类型

// infer推断每一个元素
type Arr = ['a', 'b', 'c']
type El<T extends any[]> = T extends [infer a, infer b, infer c] ? a : []
type a = El<Arr> // type a = "a"

// 推断出第一个元素
type Arr = ['a', 'b', 'c']
type First<T extends any[]> = T extends [infer first, ...any[]] ? first : []
type first = First<Arr> // type first = "a"

// 推断出最后一个元素
type Arr = ['a', 'b', 'c']
type Last<T extends any[]> = T extends [...any[], infer last] ? last : []
type last = Last<Arr> // type last = "c"

// 删除最后一个
type Arr = ['a', 'b', 'c']
type Pop<T extends any[]> = T extends [infer rest, unknown] ? rest : []
type pop = Pop<Arr> // type pop = ['a', 'b']

// 数组取反
type Arr = [1, 2, 3, 4]
type Reverse<T extends any[]> = T extends [infer first, ...infer rest] ? [...Reverse<rest>, first] : T
type rArr = Reverse<Arr> // type rArr = [4, 3, 2, 1]