得泛型者,得TypeScript

808 阅读2分钟

开始使用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>