Typescript手写实现工具类型

Typescript手写工具类型

起因

之前有次面试的时候和面试官说了句熟悉Typescript,

面试官:那你手写实现一下Pick类型

我:………

面试官:……..

还是要保持一颗谦虚学习的心🤣🤣🤣🤣🤣

工具类型

Typescript提供一些官方工具类型,这些工具类型全局可用, 无需手动导入,通过使用这些工具类型可以减少很多重复工作,提高效率和代码整洁度。

Typescript工具类型详细介绍可以见TypeScript实用工具

手写工具类型

Pick<Type, Keys>

type MyPick<Type, Keys extends keyof Type> = {
    [P in Keys]: Type[P]
}

demo

Omit<Type, Keys>

type MyOmit<Type, Keys extends keyof Type> = {
    [P in Exclude<keyof Type, Keys>]: Type[P]
}

Omit的作用与Pick相反,也可以借助Pick来实现Omit。

type MyOmit<Type, Keys extends keyof Type>  = Pick<Type, Exclude<keyof Type, Keys>>

demo

Recod<K, T>

type MyRecord<K extends string | number | symbol, T> = {
    [R in K]: T
}

demo

Exclude<T, U>

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

demo

Extract<T, U>

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

demo

NonNullable

type MyNonNullable<T> = Exclude<T, undefined | null>
// 即
type MyNonNullable<T> = T extends null | undefined ? never : T;
// 或者
type MyNonNullable<T> = T & {}

demo

Required

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

这里的-?符号看起来很容易让人懵逼,事实上这的- 号是控制映射类型修饰符的,除此之外还有+号,可以通过-+号来修改属性readonly或者属性可选。 也就是说上面的-?意思是remove ? ,同理,+?+readonly分别是添加属性可选、添加属性可读的意思,但是通常情况下我们可以省略+,因为不写和写+的效果是一样的。

关于这部分内容可见: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#improved-control-over-mapped-type-modifiers

demo

Partial

根据上面的介绍,我们可以很容易想到利用+?来实现Partial,也可以省略+

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

demo

Readonly

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

我们也可以写出移除readonly属性的工具类型:

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

甚至可以实现一个让数组里每个元素都readonly的工具类型。

type MyReadonlyArray<T> = {
    +readonly [P in number]: T
}

demo

Parameters

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

ReturnType

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

ConstructorParameters

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

demo

InstanceType

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

demo

ThisParameterType

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

demo

OmitThisParameter

type MyOmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T

demo

参考

Documentation - Utility Types

Documentation - TypeScript 2.8

Documentation - TypeScript 4.7

最后更新于