TypeScript——泛型

83 阅读2分钟

一、前言

如果你能看得懂 JS 的函数,那你就能看懂 TS 的泛型。
JS 的函数

const f = (a, b) => a + b
const result = f(1, 2)

TS 的泛型

type F<A, B> = A | B
type Result = F<string, number>

image.png

二、了解泛型

1. 泛型的本质

函数的本质:推后执行的、部分待定的代码
泛型的本质:推后执行的、部分待定的类型

2. 为什么需要泛型

没有泛型,有些奇怪的需求就无法满足。
没有泛型的类型系统,就如同没有函数的编程语言。

image.png

三、使用泛型

1. 一星难度的泛型

type Union<A, B> = A | B
type Union3<A, B, C> = A | B | C
type Intersect<A, B> = A & B
type Intersect3<A, B, C> = A & B & C
interface List<A> {
  [index: number]: A
}
interface Hash<V> {
  [key: string]: V
}

type X = Hash<string>

2. 在泛型中使用 extends

extends 读作继承包含于

type LikeString<T> = T extends string ? true : false //这种称为条件类型
type R1 = LikeString<'hi'> // true
type R2 = LikeString<true> // false

type Person = { name: string }
type LikePerson<T> = T extends Person ? 'yes' : 'no' //这种称为条件类型
type T1 = LikePerson<{ name: 'frank', xxx: 1 }> // yes
type T2 = LikePerson<{ xxx: 1 }> // no

extends 规则:

  • 若 T 为 never,则表达式的值为 never。
  • 若 T 为联合类型,则分开计算。(就好比乘法的分配律注意:只对泛型有效
// 若 T 为 never,则表达式的值为 never。
type ToArray<T> = T extends unknown ? T[] : never
type Result = ToArray<never>
// type Result = never extends unknown ? ...
// type Result = 空集没有元素直接返回 never
// type Result = never
// 若 T 为联合类型,则分开计算。
type ToArray<T> = T extends unknown ? T[] : never
type Result = ToArray<string | number>
// type Result = (string | number) extends unknown ? ...
// type Result = (string extends unknown ? ...)
//             | (number extends unknown ? ...)
// type Result = string[] | number[]

3. 在泛型中使用 keyof

type Person = { name: string, age: number }
type GetKeys<T> = keyof T
type Result = GetKeys<Person>
// ^-- 'name' | 'age'

4. 在泛型中使用 extends keyof

type Person = { name: string, age: number }
type GetKeyType<T, K extends keyof T> = T[K]
type Result1 = GetKeyType<Person, 'name'>
// ^-- string
type Result2 = GetKeyType<Person, 'age'>
// ^-- number

5. 使用映射类型 in

type Person = { id: number, name: string, age: number }

//全部属性加上readonly
type Readonly<T> = { 
  readonly [K in keyof T]: T[K]
}
type X1 = Readonly<Person>

//全部属性可选填
type Partial<T> = { 
  [K in keyof T] ?: T[K]
}
type X2 = Partial<Person>

//全部属性必填
type Required<T> = { 
  [K in keyof T] -?: T[K]
}
type X3 = Required<Person>

//实现 Record
type Record<Key extends string | number | symbol, Value> = { 
  [K in Key]: Value
}
type X4 = Record<string, number>

// 取集合不共有的属性
type Exclude<A, B> = A extends B ? never : A 
type X5 = Exclude<1 | 2 | 3, 1 | 2> // 3

// 取集合共有的属性
type Extract<A, B> = A extends B ? A : never
type X6 = Extract<1 | 2 | 3, 2 | 4> // 2

// 两种方法实现 忽略指定属性。
type Omit<T, K> = {
  [Key in keyof T as (Key extends K ? never : Key)] : T[Key]
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type X7 = Omit<Person, 'name' | 'age'> //类型为{id: number}

// 取出指定属性
type Pick<T, K extends keyof T> = {
  [Key in K]: T[Key]
}
type X8 = Pick<Person, 'age'> //类型为{age: number}

6. 使用 -readonly

把对象所有属性变为可写的。

type Mutable<T> = {
  -readonly [K in keyof T] : T[K]
}
type Y = Mutable<Readonly<Person>>

7. 总结

image.png