1. 入门
1.1 泛型就像是函数
const f = (a, b) => a + b
const result = f(1, 2)
type F<A, B> = A | B
type Result = F<string, number>
console.log(1)
const f1 = () => console.log(1)
setTimeout(() => {
f1()
}, 3000)
const f2 = (x) => console.log(x)
f2(2222)
const f3 = (fn) => fn(1)
f3(console.log)
const f4 = (fn, x) => fn(x)
f4(console.log, 1)
1.2 为什么会有泛型
function echo(whatever: number | string | boolean) {
switch (typeof whatever) {
case 'number':
return whatever
case 'string':
return whatever
case 'boolean':
return whatever
}
}
1.3 难度为一星的泛型
interface List<A> {
[index: number]: A
}
interface X {
[index: number]: string
}
interface Hash<V = string> {
[key: string]: V
}
type Person = {
name: string
}
type v = Hash
type v1 = Hash<Person>
1.4 在泛型中使用extends
/**
* 规则
* 1. 若T为never,则表达式的值为never
* 2. 若T为联合类型,则分开计算 见以下 ToArray
*/
/**
* 只对泛型有效
* 1. 类似于乘法中的零 0 X C = 0
* 2. 类似于乘法中的分配率 (A + B) X C = A X C + B X C
*/
type Person = { name: string }
// extends 表示 T <= string
type LikeString<T> = T extends string ? true : false
type LikeNumber<T> = T extends number ? 1 : 2
type LikePerson<T> = T extends Person ? 1 : 2
type R1 = LikeString<'hi'> // true
type R2 = LikeString<true> // false
type S1 = LikeNumber<6666> //1
type S2 = LikeNumber<false> // 2
type T1 = LikePerson<{ name: 'lwz'
type T2 = LikePerson<{ xxx: 1 }> // no
type X1 = LikeNumber<never>
type ToArray<T> = T extends unknown ? T[] : never
type Result = ToArray<string | number>
// 当传递的类型为never时, 并不会进入后面的类型判断,直接返回never
type Result1 = ToArray<never> // Result1 为 never 类型
// type Result = string | number extends unknown ? ...
// type Result = string extends unknown ? string[] : never
// |
// number extends unknown ? number[] : never
// 因此等价于
// type Result = string[] | number[]
/**
* 1. <string | number>[]
* 2. string[] | number[] √
*/
// function f(a: T): ToArray<T> {
// if (typeof a === 'string') {
// return string[]
// } else if (typeof a === 'number') {
// return number[]
// }
// }
1.5 在泛型中使用keyof
type Person = { name: string
type GetKeys<T> = keyof T
type Result = GetKeys<Person>
// 验证方式
// const p: Result = ''
1.6 在泛型中使用extends keyof
type Person = { name: string; age: number }
type GetKeyType<T, K extends keyof T> = T[K]
type Result = GetKeyType<Person, 'name'>
type X = Person['name']
2. 进阶
2.1 如何使用映射类型
type Person = { id?: number; name: string; age: number }
type X1 = Readonly<Person>
type X2 = Partial<Person>
type X3 = Required<Person>
type Required<T> = {
[k in keyof T]-?: T[k]
}
type Record<Key extends string | number | symbol, Value> = {
[k in Key]: Value
}
type X4 = Record<string, string>
type Y = {
[k: string]: number
}
type Z = {
[k in string]: number
}
type YK = keyof Y
const obj = {
1: "abc",
2: "cba"
}
type ZK = keyof Z
1.3 难度为3星的泛型
type Person = { id: number; name: string; age: number }
type X5 = Exclude<1 | 2 | 3, 1 | 2>
type Extract<A, B> = A extends B ? A : never
type X6 = Extract<1 | 2 | 3, 2 | 4>
type Omit<T, Key extends keyof T> = Pick<T, Exclude<keyof T, Key>>
type X7 = Omit<Person, "name" | "age">
type Pick<T, Keys extends keyof T> = {
[K in Keys]: T[K]
}
type X8 = Pick<Person, "name" | "age">
1.4 如何使用readonly
type Person = {
readonly id: number
readonly name: string
readonly age: number
}
type Mutable<T> = {
-readonly [k in keyof T]: T[k]
}
type X = Mutable<Person>