开始使用ts,但是泛型一直弄得糊里糊涂,汇总一些常见用法,窥探泛型工具类的实现原理,使其理解更加深入
一、泛型基础
1、泛型定义的理解
- 泛型 , 用来在代码执行时传入的类型,来确定结果, 即 泛型就是对类型编程
2、默认参数
type A<T = string> = Array<T>
const cc: A<number> = [1] // ok
二、泛型常规用法案例
1、泛型在函数中的用法
function createArray<T>(len: number, value: T): T[] {
let result = []
for (let i = 0; i < len; i++) {
result.push(value)
}
return result
}
let arr = createArray(3, 'HELLO')
// 多个泛型 元组的交换 [boolean,number] = [number,boolean]
const swap = <T, K>(tuple: [T, K]): [K, T] => {
return [tuple[1], tuple[0]]
}
swap<number, number>([1, 2])
// any 的妙用
function tuplify<T extends any[]>(...param: T) {
return param
}
tuplify(22, 'sring')
2、泛型在类中的用法
interface GenericInterface<U> {
value: U
getIdentity: () => U
}
class IdentityClass<T> implements GenericInterface<T> {
value: T
constructor(value: T) {
this.value = value
}
getIdentity(): T {
return this.value
}
}
const myNumberClass = new IdentityClass<Number>(68)
console.log(myNumberClass.getIdentity()) // 68
const myStringClass = new IdentityClass<string>('Semlinker!')
console.log(myStringClass.getIdentity()) // Semlinker!
三、泛型工具类的实现
1、Partial 把属性都变成可选的
- keyof 可以用来取得一个对象接口的所有 key 值. in 则可以遍历枚举类型
enum Sex {
Man,
Woman,
UnKnow,
}
interface Person {
name: string
sex: Sex
age: number
}
type Partial<T> = {
[P in keyof T]?: T[P]
}
type newPartial = Partial<Person>
2、Required 将传入的属性变为必选项
- -? 去掉, 从而让这个类型变成必选项
type Required<T> = {
[P in keyof T]-?: T[P]
}
3、Mutable 将 T 的所有属性的 readonly 移除
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
4、Readonly 将传入的属性变为只读选项
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
5、Record 将 K 中所有的属性的值转化为 T 类型
type Record<K extends keyof any, T> = { [P in K]: T }
// 案例:
/**
* interface Family {
* parent: Person,
* mom: Person,
* child: Person
* }
*/
type Family = Record<'parent' | 'mom' | 'child', Person>
6、Pick 从 T 中取出 一系列 K 的属性
type Pick<T, K extends keyof T> = { [P in K]: T[P] }
// eg
interface Person {
name: string
age: number
sex?: "male" | "female" | "other";
}
/**
* equivalent to { name: string }
*/
type SimplePersonInfo = Pick<Person, 'name'>
7、Exclude 从T 中排除 U
- T extends U ? X : Y 如果 T 是 U 的子类型的话,那么就会返回 X,否则返回 Y
- T extends U ? X : Y, T 可能是 A | B 的联合类型, 那实际情况就变成(A extends U ? X : Y) | (B extends U ? X : Y)
type Exclude<T, U> = T extends U ? never : T
// eg
type T = Exclude<1 | 2, 1 | 3> // -> 2
8、Extract 从 T 中提取出 U
type Extract<T, U> = T extends U ? T : never
9、Omit用之前的 Pick 和 Exclude 进行组合, 实现忽略对象某些属性功能
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
// eg
/**
* equivalent to { age: number }
*/
type Foo = Omit<{ name: string; age: number }, 'name'>
10、ReturnType 得到一个函数的返回值类型。
- 在条件类型语句中, 我们可以用 infer 声明一个类型变量并且对它进行使用
- 其实这里的 infer R 就是声明一个变量来承载传入函数签名的返回值类型
infer
的作用是让TypeScript
自己推断,并将推断的结果存储到一个类型变量中,infer
只能用于extends
语句中。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any
// eg
function foo(x: number): Array<number> {
return [x]
}
type fn = ReturnType<typeof foo>