TypeScript - 内置工具

102 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

内置工具

TypeScript的目的是为JavaScript添加一套类型校验系统,因为JavaScript本身的灵活性,也让TypeScript类型系统不得不增加更复杂的功能以适配JavaScript的灵活性

也就是说TypeScript是一种可以支持类型编程的类型系统,同时为了方便我们使用TypeScript, TS提供了大量的内置工具以简化我们对应的类型操作

Partial<Type>

用于构造一个Type下面的所有属性都设置为可选的类型

使用

interface IUser {
  name: string;
  age: number;
}

type User = Partial<IUser>
/*
  type User = {
    name?: string | undefined;
    age?: number | undefined;
  }
*/

实现

interface IUser {
  name: string;
  age: number
}

type MyPartial<T> = {
  [K in keyof T]?: T[K]
}

type User = MyPartial<IUser>

Required<Type>

用于构造一个Type下面的所有属性全都设置为必填的类型,这个工具类型跟 Partial 相反

使用

interface IUser {
  nam?: string;
  age?: number;
}

type User = Required<IUser>
/*
  =>
  type User = {
    nam: string;
    age: number;
  }
*/

实现

interface IUser {
  nam?: string;
  age?: number;
}

type MyRequired<T> = {
  [K in keyof T]-?: T[K]
}

type User = MyRequired<IUser>

Readonly<Type>

用于构造一个Type下面的所有属性全都设置为只读的类型,意味着这个类型的所有的属性全都不可以重新赋值

使用

interface IUser {
  nam: string;
  age: number;
}

type User = Readonly<IUser>
/*
  =>
  type User = {
    readonly nam: string;
    readonly age: number;
  }
*/

实现

interface IUser {
  nam: string;
  age: number;
}

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

type User = MyReadonly<IUser>

Record<Keys, Type>

使用

interface IUser {
  nam: string;
  age: number;
}

type Names = 'Alex' | 'Steven' | 'Jhon'

type User = Record<Names, IUser>
/*
  =>
  type User = {
    Alex: IUser;
    Steven: IUser;
    Jhon: IUser;
  }
*/

实现

interface IUser {
  nam: string;
  age: number;
}

type Names = 'Alex' | 'Steven' | 'Jhon'

// keyof any -> 返回所有可以作为索引值的类型组成的联合类型
// keyof any --> number | string | symbol
// K extends keyof any 可以确保K是字符串类型或数值类型或symbol类型或他们的联合类型
// 也就意味着K 可以在映射类型中通过in关键字进行遍历
type MyRecord<K extends keyof any, T> = {
  // P in 联合类型 -- 取出联合类型中的每一项值并使用
  // keyof 对象 -- 得到对象key组成的联合类型
  [P in K]: T
}

type User = MyRecord<Names, IUser>

Pick<Type, Keys>

用于构造一个类型,它是从Type类型里面挑了一些属性Keys

使用

interface IUser {
  name: string;
  age: number;
  address: string;
}

type Keys = 'name' | 'age'

type User = Pick<IUser, Keys>
/*
  =>
  type User = {
    name: string;
    age: number;
  }
*/

实现

interface IUser {
  name: string;
  age: number;
  address: string;
}

type Keys = 'name' | 'age'

// 在这里并不需要约束T 一定是对象类型 即T extends {}
// 因为只有对象才可以执行keyof
// 所以如果T不是对象,那么在执行MyPick的时候 就会报错
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P]
}

type User = MyPick<IUser, Keys>

Omit<Type, Keys>

用于构造一个类型,它是从Type类型里面过滤了一些属性Keys

使用

interface IUser {
  name: string;
  age: number;
  address: string;
}

type Keys = 'address'

type User = Omit<IUser, Keys>
/*
  =>
  type User = {
    name: string;
    age: number;
  }
*/

实现

interface IUser {
  name: string;
  age: number;
  address: string;
}

type Keys = 'address'

type MyOmit<T, K> = {
  [P in keyof T as P extends K ? never: P]: T[P]
}

type User = MyOmit<IUser, Keys>

Exclude<UnionType, ExcludedMembers>

用于构造一个类型,它是从UnionType联合类型里面排除了所有可以赋给ExcludedMembers的类型

使用

type Key = 'name' | 'age' | 'address'

type ExcludeKey = Exclude<Key, 'address'> // => typeof ExcludeKey -> 'name' | 'age

实现

type Key = 'name' | 'age' | 'address'

// 在MyExclude中T传入的值是联合类型
// 所以这里会使用到条件类型判断中的联合类型扩散
// 当生成的联合类型中有never的时候, never类型会被自动移除
type MyExclude<T, U> = T extends U ? never : T

type ExcludeKey = MyExclude<Key, 'address'>

Extract<Type, Union>

用于构造一个类型,它是从Type类型里面提取了所有可以赋给Union的类型

使用

type Key = 'name' | 'age' | 'address'

type ExtractKey = Extract<Key, 'address'> // typeof ExtractKey -> 'address'

实现

type Key = 'name' | 'age' | 'address'

type MyExtract<T, U> = T extends U ? T : never;

type ExtractKey = MyExtract<Key, 'address'>

NonNullable<Type>

用于构造一个类型,这个类型从Type中排除了所有的null、undefined的类型

使用

type Key = 'name' | 'age' | null | undefined

type Result = NonNullable<Key>
// type Result = "name" | "age"

实现

type Key = 'name' | 'age' | null | undefined

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

type Result = MyNonNullable<Key>

ReturnType<Type>

用于构造一个含有Type函数的返回值的类型

使用

function foo(num: number) {
  return num + ''
}

type Result = ReturnType<typeof foo>
// type Result = string

实现

function foo(num: number) {
  return num + ''
}

type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never

type Result = MyReturnType<typeof foo>

InstanceType<Type>

用于构造一个由所有Type的构造函数的实例类型组成的类型

使用

class Dog {}
class Cat {}

function factoryFn<T extends new (...args: any[]) => any>(ctor: T, ...params: any[]): InstanceType<T> {
  return new ctor(...params)
}

const instance1 = factoryFn(Dog)
const instance2 = factoryFn(Cat)

实现

class Dog {}
class Cat {}

type MyInstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : never

function factoryFn<T extends new (...args: any[]) => any>(ctor: T, ...params: any[]): MyInstanceType<T> {
  return new ctor(...params)
}

const instance1 = factoryFn(Dog)
const instance2 = factoryFn(Cat)

ThisParameterType<Type>

传入一个函数,并取出传入的this所对应的类型

使用

function foo(this: string) {
  console.log('foo fun')
}

type ThisParameter = ThisParameterType<typeof foo>
// type ThisParameter = string

实现

function foo(this: string) {
  console.log('foo fun')
}

type MyThisParameterType<T extends (this: any, ...args: any[]) => any> = T extends (this: infer P, ...args: any[]) => any ? P : never

type ThisParameter = MyThisParameterType<typeof foo>

OmitThisParameter<Type>

移除函数中的this类型参数

使用

function foo(this: string, name: string, age: number) {
  console.log('foo fun')
}

type ThisParameter = OmitThisParameter<typeof foo>
// type ThisParameter = (name: string, age: number) => void

实现

function foo(this: string, name: string, age: number) {
  console.log('foo fun')
}

// 如果不存在this,那么ThisParameterType<T>的返回值 就是unknown
// 在进行...args: infer A 类型推断的时候,this的类型会被自动抹除
type MyOmitThisParameter<T extends (...args: any[]) => any> = unknown extends ThisParameterType<T> ? T :
  T extends (...args: infer A) => infer R ? (...args: A) => R : unknown

type ThisParameter = MyOmitThisParameter<typeof foo>

ThisType<Type>

这个类型不返回一个转换过的类型,它被用作标记一个上下文的this类型

使用

interface IState {
  name: string
  age: number
}

interface IStore {
  state: IState
  printName: () => void
  printAge: () => void
}

// ThisType<IState> -> 对象store中的所有this的类型都是IState
const store: IStore & ThisType<IState> = {
  state: {
    name: 'Klaus',
    age: 23
  },

  printName() {
    console.log(this.name)
  },

  printAge() {
    console.log(this.age)
  }
}

store.printName.call(store.state)
store.printAge.call(store.state)

Awaited<Type>

这种类型是为了模拟像async函数中的await或Promises上的.then()方法这样的操作

Awaited<Type>会递归的对Promise进行解包操作

使用

type A = Awaited<Promise<string>> // typeof A -> string

type B = Awaited<Promise<Promise<number>>> // typeof B -> number

type C = Awaited<boolean | Promise<number>> // typeof C -> boolean | number

Parameters<Type>

返回由函数参数类型组成的元组类型

使用

type T0 = Parameters<() => string> // type T0 = []

type T1 = Parameters<(s: string | number) => void> // type T1 = [s: string | number]

实现

type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer A) => any ? A : never

type T0 = MyParameters<() => string>

type T1 = MyParameters<(s: string | number) => void>

ConstructorParameters<Type>

返回构造函数的参数所组成的元组类型

使用

class Person {
  name: string
  age: number

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

type T1 = ConstructorParameters<typeof Person>
// type T1 = [name: string, age: number]

实现

class Person {
  name: string
  age: number

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

type MyConstructorParameters<T extends new(...args: any[]) => void> = T extends new(...args: infer R) => void ? R : never

type T1 = MyConstructorParameters<typeof Person>