TypeScript内置高阶类型

268 阅读3分钟

Pick

将T类型部分key的联合类型K组合成一个新的类型

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

usage

type obj = {
  name: string,
  age: number,
  hobby: Array
}

type obj1 = Pick<obj, 'name'|'age'>
type obj1 = {
  name: string,
  age: number,
}

Omit

从类型T 中 除去指定属性类型K

type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P]; }
// 使用Pick实现
type MyOmit1<T, K> = Pick<T, Exclude<keyof T, K>>

usage

type obj = {
  name: string,
  age: number,
  height: number
}

type res = Omit<obj, 'name'|'age'>
type res = {
  height: number
}

Exclude

将T联合类型在U联合类型中不存在的参数取出组合成一个新的类型

type Exclude<T, U> = T extends U ? never : T

Usage

type U1 = 'age'|'name'|'hobby'
type U2 = 'age'|'name'

type U3 = Exclude<U1, U2>
type U3 = 'hobby'

Extract

将T联合类型在U联合类型中出现的参数组合成一个新的类型

type Extract<T, U> = T extends U ? T : never

Usage

type U1 = 'age'|'name'|'hobby'
type U2 = 'age'|'height'

type U3 = Extract<U1, U2>
type U3 = 'age'

Partial

将类型T的所有属性标记为可选属性

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

Usage

type obj = {
  name: string,
  age: number,
  height: number
}

type P = Partial<obj>
type P = {
    name?: string | undefined;
    age?: number | undefined;
    height?: number | undefined;
}

Required

将类型T的所有属性标记为必选属性

type Required<T> = { [P in keyof T]-?: T[P]; }

Usage

type obj = {
  name?: string,
  age?: number,
  height: number
}

type r = Required<obj>
type r = {
    name: string;
    age: number;
    height: number;
}

Readonly

将类型T的所有属性标记为readonly类型

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

Usage

type obj = {
  name: string,
  age: number,
  height: number
}

type r = Readonly<obj>
type r = {
    readonly name: string;
    readonly age: number;
    readonly height: number;
}

Record

将类型K作为对象的属性key 将类型T作为对象的属性值value

type Record<K extends keyof any, T> = { [P in K]: T; }

Usage

type Key = 'name'|'age'
type Value = string
type R = Record<Key, Value>

const r: R = {
  name: 'name',
  age: 18
}

NonNullable

将类型T中的null和undefined去掉组合成新的类型

type NonNullable<T> = T extends null | undefined ? never : T

Usage

type r = NonNullable<null|undefined|'name'|'age'>
type r = 'name'|'age'

Parameters

获取函数类型T的参数类型 返回一个元组

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never

Usage

type res = MyParameters<(name: string, age: number) => void>
type a = [name: string, age: number]

ReturnType

获取函数类型T的返回类型

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

Usage

type res = ReturnType<() => () => 'haha'>
type res = () => 'haha'

ConstructorParameters

获取对象T参数的类型 返回元组

type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never

Uasge

class Animal {
  constructor(name:string, age:number) {

  }
}

type res = ConstructorParameters<typeof Animal>
type res = [name: string, age: number]

InstanceType

推断实例对象返回的类型

type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any

Usage

class Animal {
  constructor(public name: string, public age: number) {
    this.name = name
    this.age = age
  }

  getAge():number {
    return this.age
  }

  getName():string {
    return this.name
  }
}

// 类型“{ name: string; }”缺少类型“Animal”中的以下属性: age, getAge, getName
const a: InstanceType<typeof Animal> = {
  name: 'a',
}

Uppercase

转换字符串字面量全部为大写字母

type Uppercase<S extends string> = intrinsic;

Lowercase

转换字符串字面量全部为小写字母

type Lowercase<S extends string> = intrinsic;

Capitalize

转换字符串字面量的首字母为大写字母

type Capitalize<S extends string> = intrinsic;

Uncapitalize

转换字符串字面量的首字母为小写字母

type Uncapitalize<S extends string> = intrinsic;

Usage

type S0 = Uppercase<'Hello'>; // => 'HELLO'
type S1 = Lowercase<S0>; // => 'hello'
type S2 = Capitalize<S1>; // => 'Hello'
type S3 = Uncapitalize<S2>; // => 'hello'

在上述示例中,这 4 种操作字符串字面量工具类型的实现都是使用 JavaScript 运行时的字符串操作函数计算出来的,且不支持语言区域设置。以下代码是这 4 种字符串工具类型的实际实现。intrinsic意为内部的

function applyStringMapping(symbol: Symbol, str: string) {

  switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
    case IntrinsicTypeKind.Uppercase:
      return str.toUpperCase();

    case IntrinsicTypeKind.Lowercase:
      return str.toLowerCase();

    case IntrinsicTypeKind.Capitalize:
      return str.charAt(0).toUpperCase() + str.slice(1);

    case IntrinsicTypeKind.Uncapitalize:
      return str.charAt(0).toLowerCase() + str.slice(1);

  }

  return str;