Typescript 高级用法

128 阅读4分钟

Partial => MyPartial

1.所有的变成可选
2.keyof主要核心转化联合类型,进行+?

type Foo = {
  a: string
  b: number
  c: boolean
}

const a: MyPartial<Foo> = {}

const b: MyPartial<Foo> = {
  a: 'aaaaa'
}

const c: MyPartial<Foo> = {
  b: 123
}

const d: MyPartial<Foo> = {
  b: 123,
  c: true
}

const e: MyPartial<Foo> = {
  a: 'aaaaa',
  b: 123,
  c: true
}



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

Required => MyRequired

1.所有的变成必选
2.需要通过keyof将其转化为联合类型,通过-?将可选去掉

type Foo = {
  a?: string
  b?: number
  c?: boolean
}


const a: MyRequired<Foo> = {}
// Error

const b: MyRequired<Foo> = {
  a: 'asdf'
}
// Error

const c: MyRequired<Foo> = {
  b: 123
}
// Error

const d: MyRequired<Foo> = {
  b: 123,
  c: true
}
// Error

const e: MyRequired<Foo> = {
  a: 'asdf',
  b: 123,
  c: true
}


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

Readonly => MyReadonly

readonly此为核心思想

type Foo = {
  a: string
}

const a:Foo = {
  a: '123',
}
a.a = 'bigfrontend.dev'
// OK

const b:MyReadonly<Foo> = {
  a: '123'
}
b.a = 'bigfrontend.dev'
// Error


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

Record => MyRecord

1.将联合类型转化为对象
2.判断是否在T中,然后赋值

type Key = 'a' | 'b' | 'c'

const a: Record<Key, string> = {
  a: '111',
  b: '222',
  c: '333'
}
a.a = 'bigfrontend.dev' // OK
a.b = 123 // Error
a.d = '123123' // Error

type Foo = MyRecord<{a: string}, string> // Error


`keyof any == string | number | symbol`
type MyRecord<T extends keyof any,V> = {
    [P in T]: V
}

Pick => MyPick

1.在K进行参数校验
2.循环T 进行取值

type Foo = {
  a: string
  b: number
  c: boolean
}

type A = MyPick<Foo, 'a' | 'b'> // {a: string, b: number}
type B = MyPick<Foo, 'c'> // {c: boolean}
type C = MyPick<Foo, 'd'> // Error


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

Exclude => MyExclude

排除 通过extends去进行类似遍历对比 判断是否有,如果有则返回never否则返回值

type Foo = 'a' | 'b' | 'c'

type A = MyExclude<Foo,'a'> // 'b' | 'c'
type B = MyExclude<Foo,'b'> // 'a' | 'c'
type AB = MyExclude<Foo,'a' | 'b'> // 'c'

type MyExclude<T,K> = T extends K ? never : T

Omit => MyOmit

Omit获取排除的类型
1.首先先获取排除的联合类型
2.通过Pick获取排除后的对象

type Foo = {
  a: string
  b: number
  c: boolean
}

type A = MyOmit<Foo, 'a' | 'b'> // {c: boolean}
type B = MyOmit<Foo, 'c'> // {a: string, b: number}
type C = MyOmit<Foo, 'c' | 'd'> // {a: string, b: number}


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


Extract => MyExtract

  1. 这个和Exclude相反,思路看Exclude
type Foo = 'a' | 'b' | 'c'

type A = MyExtract<Foo, 'a'> // 'a'
type B = MyExtract<Foo, 'a' | 'b'> // 'a' | 'b'
type C = MyExtract<Foo, 'b' | 'c' | 'd' | 'e'>  // 'b' | 'c'
type D = MyExtract<Foo, never>  // never

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

# NonNullable

1.核心思路通过extends进行循环对比相等则返回never

type Foo = 'a' | 'b' | null | undefined

type A = MyNonNullable<Foo> // 'a' | 'b'

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

type MyNonNullable<T,P extends any = T> = T extends P ?
 T extends null ? 
  never : T extends undefined ? never : T : never

# Parameters

type Foo = (a: string, b: number, c: boolean) => string

type A = MyParameters<Foo> // [a:string, b: number, c:boolean]
type B = A[0] // string
type C = MyParameters<{a: string}> // Error

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

ConstructorParameters

[Parameters]处理的是function type。 与之类似,ConstructorParameters<T>针对的是class,返回constructor function T的其参数type组成的tuple type。

class Foo {
  constructor (a: string, b: number, c: boolean) {}
}

type C = MyConstructorParameters<typeof Foo> 
// [a: string, b: number, c: boolean]

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

ReturnType

[Parameters]处理的是参数, ReturnType<T>,正如起名所述,处理的是function type T的返回值type

思路:
1.通过extends进行函数比对 2.其次通过infer变量暂存起来(只能在extends)中使用
2.比对成功则返回 infer变量

type Foo = () => {a: string}

type A = MyReturnType<Foo> // {a: string}
    
type MyReturnType<T extends () => any> = T extends () => infer P ? P : never

InstanceType

对于constructor function type T,InstanceType<T> 返回其instance type。

思路: 1.

class Foo {}
type A = MyInstanceType<typeof Foo> // Foo
type B = MyInstanceType<() => string> // Error
    
type MyInstanceType<T extends new () => any> = T extends new () => infer P ? P : never

ThisParameterType

对于function type T,ThisParameterType<T>返回this type。 如果没有指定,则使用unknown

function Foo(this: {a: string}) {}
function Bar() {}

type A = MyThisParameterType<typeof Foo> // {a: string}
type B = MyThisParameterType<typeof Bar> // unknown
    
type MyThisParameterType<T> = T extends (this: infer P) => any ? P : unknown

OmitThisParameter

Function.prototype.bind()返回一个this已经bind过后的function。 对于这种情况,可以用OmitThisParameter<T>来增加type信息。

function foo(this: {a: string}) {}
foo() // Error

const bar = foo.bind({a: '123123123'})
bar() // OK


type Foo = (this: {a: string}) => string
type Bar = MyOmitThisParameter<Foo> // () => string
    
type MyOmitThisParameter<T extends (...args: any) => any> = T extends (...args: any) => infer P ? () => P : never

FirstChart

type A = FirstChar<'ABA'> // 'A'
type B = FirstChar<'dAA'> // 'd'
type C = FirstChar<''> // never
    
    
 type FirstChar<T extends string> = T extends `${infer L}${infer R}` ? L : never

LastChar

type A = LastChar<'VVE'> // 'E'
type B = LastChar<'dev'> // 'v'
type C = LastChar<''> // never
   
type LastChar<T extends string, P = never> = T extends `${infer L}${infer R}` ? LastChar<R, L> : P

TupleToUnion

type Foo = [string, number, boolean]

type Bar = TupleToUnion<Foo> // string | number | boolean
   
type TupleToUnion<T extends any[], P = T[0]> = T extends [infer L, ...infer R] ? TupleToUnion<R, P | L> : P

FirstItem

type A = FirstItem<[string, number, boolean]> // string
type B = FirstItem<['B', 'C', 'D']> // 'B'
    
type FirstItem<T extends any[]> = T extends [infer L, ...infer R] ? L : never

LastItem

type A = LastItem<[string, number, boolean]> // boolean
type B = LastItem<['B', 'C', 'D']> // 'D'
type C = LastItem<[]> // never
    
type LastItem<T extends any[]> = T extends [...infer L,infer R] ? R : never
type LastItem<T extends any[],Prev extends any = never> = T extends [infer L,...infer R] ? LastItem<R,L> : Prev

IsNever

type A = IsNever<never> // true
type B = IsNever<string> // false
type C = IsNever<undefined> // false
    
type IsNever<T> = [T] extends [never] ? true : false

StringToTuple

type A = StringToTuple<'BCD.EFG'> // ['B', 'C', 'D', '.', 'E', 'F','G']
type B = StringToTuple<''> // []
    
type StringToTuple<T extends string, A extends any[] = []> = T extends `${infer L}${infer R}` ? StringToTuple<R, [...A, L]> : A
type StringToTuple<T extends string> = T extends `${infer L}${infer R}` ? [L, ...StringToTuple<R>] : []

LengthOfTuple

type A = LengthOfTuple<['B', 'C', 'D']> // 3
type B = LengthOfTuple<[]> // 0
type LengthOfTuple<T extends any[], A extends any[] = []> = T extends [infer L, ...infer R] ? LengthOfTuple<R,[...A,undefined]> : A["length"]

LengthOfString

type A = LengthOfString<'BCD.EFG'> // 7
type B = LengthOfString<''> // 0
type LengthOfString<T extends string>=StringToTuple<T>['length']

UnwrapPromise

type A = UnwrapPromise<Promise<string>> // string
type B = UnwrapPromise<Promise<null>> // null
type C = UnwrapPromise<null> // Error

type UnwrapPromise<T> = T extends Promise<infer L> ? L : never

ReverseTuple

type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string]
type B = ReverseTuple<[1,2,3]> // [3,2,1]
type C = ReverseTuple<[]> // []
    
type ReverseTuple<T extends any[]> = T extends [infer L, ...infer R] ? [...ReverseTuple<R>, L] : []

// 参考 StringToTuple

Flat

type A = Flat<[1,2,3]> // [1,2,3]
type B = Flat<[1,[2,3], [4,[5,[6]]]]> // [1,2,3,4,5,6]
type C = Flat<[]> // []
    
type Flat<T extends any[], A extends any[] = []> = T extends [infer L, ...infer R] ?
  // L extends any[] ? Flat<[...L, ...R], A> : Flat<R, [...A, L]>
  FlatFront<L, R, A>
  : A
type FlatFront<T, R extends any[], A extends any[] = []> = T extends any[] ? Flat<[...T, ...R], A> : Flat<R, [...A, T]>