Summary of the 61st week - regaining ts type gymnastics

recapture ts type gymnastics

Match pattern to do extraction

  1. array type
  • Extract the type of the first element of the array
type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;
  • Extract the type of the last element of the array
type GetLast<Arr extends unknown[]> = Arr extends [...unknown[],infer Last] ? Last : never;
  • Remove the type of the last element of the array
type PopArr<Arr extends unknown[]> = Arr extends [] ? [] : Arr extends [...infer Result,unknown] ? Result : never;
  • Remove the type of the first element of the array
type ShiftArr<Arr extends unknown[]> = Arr extends [] ? [] : Arr extends [unknown,...infer Result] ? Result : never;
  1. string type
  • Check if a string starts with a prefix
type StartWith<Str extends string, Start extends string> = Str extends `${
      
      Start}${
      
      string}` ? true : false;
  • string replacement
type ReplaceStr<
  Str extends string,
  From extends string,
  To extends string
> = Str extends `${
      
      infer Prefix}${
      
      From}${
      
      infer Suffix}` ?
    ReplaceStr<`${
      
      Prefix}${
      
      To}${
      
      Suffix}`,From,To> : Str
  • Recursively remove right spaces from a string
type TrimStringRight<Str extends string> = Str extends `${
      
      infer Result}${
      
      ' '}` ? TrimStringRight<Result> : Str;
  • Recursively remove left spaces from a string
type TrimStringLeft<Str extends string> = Str extends `${
      
      ' '}${
      
      infer Result}` ? TrimStringLeft<Result> : Str;
  • Recursively remove left and right spaces in a string
type TrimString<Str extends string> = Str extends `${
      
      ' '}${
      
      infer Result}${
      
      ' '}` ? TrimString<Result> : Str;
  1. function
  • Extract the type of parameter
type FunctionArgs<Fn extends Function> = Fn extends (...args:infer Args) => unknown ? Args : never;
  • extract return value
type FunctionResult<Fn extends Function> = Fn extends (...args:any[]) => infer Result ? Result : never;
  • Extract this in the function
type FunctionThis<Fn extends Function> = Fn extends (this:infer This,...args:unknown[])=>unknown ? This : never;
  1. constructor
  • Match to extract the instance object
type GetInstanceType<Type extends new(...args:any[])=>any> = Type extends new(...args:any) => infer Result ? Result : never;
// 测试案例
interface Person{
    
    
  name: string
}
interface PersonConstructor{
    
    
  new(name:string):Person
}
type person = GetInstanceType<PersonConstructor>;
  • Extract constructor parameters
type GetInstanceParam<Type extends new(...args:any[])=>any> = Type extends new(...args:infer Result) => unknown ? Result : never;
// 测试案例
interface Person{
    
    
  name: string
}
interface PersonConstructor{
    
    
  new(name:void):Person
}
type person = GetInstanceParam<PersonConstructor>;
  1. index type
  • Extract the type of ref's value
    ts type gymnastics, extract the type of ref's value.

restructure to transform

  1. Array Type Reconstruction
  • Add elements to the back of the array
type Push<Arr extends unknown[],Ele> = [...Arr,Ele];
  • Add an element to the front of the array
type Shift<Ele, Arr extends unknown[]> = [Ele,...Arr];
  • Merge corresponding elements of two tuples with only two elements
type Concat<One extends [unknown,unknown],Two extends [unknown,unknown]> = 
One extends [infer OneFirst, infer OneSecond] ?
  Two extends [infer TwoFirst, infer TwoSecond] ? [[OneFirst,OneSecond],[TwoFirst,TwoSecond]] : []
: []
  • Merge elements corresponding to two tuples with only any number of elements
type Concat<One extends unknown[],Two extends unknown[]> = 
One extends [infer OneFirst,...infer OneOther] ?
  Two extends [infer TwoFirst,...infer TwoOther] ? [[OneFirst,TwoFirst],...Concat<OneOther,TwoOther>] : []
: [];
  1. string reconstruction
  • Convert the first element of a string to uppercase
type StringFistToUp<Str extends string> = Str extends `${
      
      infer First}${
      
      infer Other}` ? `${
      
      Uppercase<First>}${
      
      Other}` : never
  • delete a string in a string
type DeleteString<Str extends string,Ele extends string> = 
Str extends `${
      
      infer Start}${
      
      Ele}${
      
      infer End}` ? DeleteString<`${
      
      Start}${
      
      End}`,Ele> : Str
  • Function Type Reconstruction
type FunAddParam<Fn extends Function,Arg extends unknown> =
Fn extends (...args:infer Args)=>infer Result ? (...args:[...Args,Arg])=>Result : never
  1. Index type reconstruction
  • Change the Key of the index type to uppercase
type KeyUp<Obj extends Object> = {
    
    
  [Key in keyof Obj as Uppercase<Key & string>]:Obj[Key];
}
  • Record, typescript built-in Record, used to create index types.
type _Record<K extends keyof any, T> = {
    
    
  [P in K]: T
}
  • Convert the index to read-only
type ReadonlyParam<T> = {
    
    
 readonly  [P in keyof T]: T[P]
}
  • Add optional modifiers to the index
type toSelector<T> = {
    
    
  [P in keyof T]?: T[P]
}
  • Remove the read-only modifier
type RemoveReadonly<T> = {
    
    
  -readonly [P in keyof T]: T[P]
}
  • Remove the optional modifier
type ClearSelector<T> = {
    
    
  [P in keyof T]-?: T[P]
}
  • Filter by index type
type FilterValue<T extends Record<string,any>,valueType extends unknown> = {
    
    
  [Key in keyof T as T[Key] extends valueType ? Key : never]: T[Key]
}

recursive reuse as loop

  1. Promise recursive call
  • Extract the advanced type of the value type in Promise with an uncertain number of layers
type PromiseValue<T> = 
T extends Promise<infer Value>?
  PromiseValue<Value>
: T
type promise = PromiseValue<Promise<Promise<Record<string,any>>>>
  1. Array type recursion
  • tuple reversal of indeterminate length
type ReverseArr<T extends Array<unknown>> = T extends [infer First,...infer Other] ? [...ReverseArr<Other>,First] : T;
  • Find if an element exists in a tuple
type IsEqual<A,B> = (A extends B ? true : false) & (B extends A ? true : false);
type Include<Arr extends unknown[],Ele> = 
Arr extends [infer First,...infer Other] ?
  IsEqual<First,Ele> extends true ? true : Include<Other,Ele>
: false;
  • remove an element from a tuple
type RemoveArrItem<
  Arr extends unknown[],
  Item,
  Result extends unknown[] = []
> = Arr extends [infer First,...infer Other] ?
  IsEqual<Item,First> extends true ? RemoveArrItem<Other,Item,Result> : RemoveArrItem<Other,Item,[...Result,First]>
: Result
type IsEqual<A,B> = (A extends B ? true : false) & (B extends A ? true : false)
  • Build an array of the same category with a custom length
type BuildArr<
  Length extends number,
  Ele,
  Arr extends unknown[] = []
> = Arr['length'] extends Length ? Arr : BuildArr<Length,Ele,[...Arr,Ele]>
  1. String type recursion
  • Replace all specified strings in a string with another string
type Replace<
  Str extends string,
  From extends string,
  To extends string
> = Str extends `${
      
      infer Start}${
      
      From}${
      
      infer End}` ? Replace<`${
      
      Start}${
      
      To}${
      
      End}`,From,To> : Str
  • Extract each element of the string and convert it to a union type
type StrType<Str extends string,Result = never> = Str extends `${
      
      infer First}${
      
      infer Other}` ? StrType<Other,Result|First> : Result
  • reverse string type
type ReverseString<Str extends string,Result extends string = ""> = Str extends `${
      
      infer First}${
      
      infer Other}` ? ReverseString<Other,`${
      
      Result}${
      
      First}`> : Result
  1. recursion of object type (recursion of index type)

-Recursively turns the indexes of all layers into read-only
Error code, if we test it, we will find that the recursion does not go on. Because the type of ts is only calculated when it is used. Here only read-only is added to the first index, but it is not used. So it will not be calculated, we can add an Obj extends any to let it calculate.

type DeepReadonly<Obj extends Record<string,any>> = Obj extends any ? {
    
    
  readonly [Key in keyof Obj]: Obj[Key] extends Record<string,any> ? 
    Obj[Key] extends Function ? Obj[Key] : DeepReadonly<Obj[Key]>
  : Obj[Key]
} : never

Calculate the length of the array

  1. Array length realizes addition, subtraction, multiplication and division
  • add
type BuildArray<
  Length extends number,
  Ele = unknown,
  Result extends unknown[] = []
> = Result['length'] extends Length ? Result : BuildArray<Length,Ele,[Ele,...Result]>
type Add<Arr extends unknown[],Result extends unknown[] = []> = Arr extends [infer Start extends number,...infer Other]
                                                          ? Add<Other,[...BuildArray<Start>,...Result]> : 
                                                          Result['length']
type s = Add<[1,2,3]>
  • reduce
type BuildArray<
  Length extends number,
  Ele = unknown,
  Result extends unknown[] = []
> = Result['length'] extends Length ? Result : BuildArray<Length,Ele,[Ele,...Result]>
type SubTract<Num1 extends number,Num2 extends number> = BuildArray<Num1> extends [...BuildArray<Num2>,...infer Result] ? Result['length'] : never
  • take
type BuildArray<
  Length extends number,
  Ele = unknown,
  Result extends unknown[] = []
> = Result['length'] extends Length ? Result : BuildArray<Length,Ele,[Ele,...Result]>
type SubTract<Num1 extends number,Num2 extends number> = BuildArray<Num1> extends [...BuildArray<Num2>,...infer Result] ? Result['length'] : never

type Multiply<
  Num1 extends number,
  Num2 extends number,
  Result extends unknown[] = []
> = Num1 extends 0 ? Result['length'] : Multiply<SubTract<Num1,1>,Num2,[...Result,...BuildArray<Num2>]>
  • remove
type BuildArray<
  Length extends number,
  Ele = unknown,
  Arr extends unknown[] = []
> = Arr['length'] extends Length ?
    Arr :
    BuildArray<Length,Ele,[...Arr,Ele]>
type Subtract<Num1 extends number, Num2 extends number> = BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest] ?
Rest['length'] : never

type Divide<
  Num1 extends number,
  Num2 extends number,
  ResultArr extends unknown[] = []
> = Num1 extends 0 ?
    ResultArr['length'] :
    Divide<Subtract<Num1,Num2>,Num2,[unknown, ...ResultArr]>;
type divide = Divide<6,3>;
  • The type to find the length of a string
type StrLen<
  Str extends string,
  ResultArr extends unknown[] = []
> = Str extends `${
      
      string}${
      
      infer Rest}`? 
  StrLen<Rest,[...ResultArr, unknown]>
: ResultArr['length'];
type str = StrLen<'123'>;
  • compares the size of two values
type Than<
  Num1 extends number,
  Num2 extends number,
  Count extends unknown[] = []
> = Num1 extends Num2 ? false :
  Count['length'] extends Num2 ? true :
  Count['length'] extends Num1 ? false :
  Than<Num1,Num2,[unknown,...Count]>
  • Calculation of Fibonacci Sequences
type Fi<
  Left extends unknown[],
  Right extends unknown[],
  Num extends number,
  Idx extends unknown[] = [],
  > = Idx['length'] extends Num ? Right['length'] : Fi<Right,[...Left,...Right],Num,[...Idx,unknown]>

type Fib<Num extends number> = Fi<[],[1],Num,[1]>

Joint decentralization can be simplified

  1. Remove the dot from the string _ of the union type, and capitalize the first letter after _
type Tool<Str extends string> = Str extends `${
      
      infer First}_${
      
      infer Start}${
      
      infer End}` ? Tool<`${
      
      First}${
      
      Uppercase<Start>}${
      
      End}`> : Str
type item = Tool<'aa_bb_cc_dd'>;
  1. Judging the joint type
type Tool<A, B = A> =
A extends A?
  [B] extends [A] ? false : true
: never
  1. BEM
    BEM is the css naming convention
type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;
//会转换成
guang__aaa--warning guang__bbb--success
type BEM<Ele1 extends string,Ele2 extends string[],Ele3 extends string[]> = `${
      
      Ele1}__${
      
      Ele2[number]}--${
      
      Ele3[number]}`
  1. AllCombinations
type Combination<A extends string, B extends string> =
    | A
    | B
    | `${
      
      A}${
      
      B}`
    | `${
      
      B}${
      
      A}`;
type AllCombinations<A extends string, B extends string = A> = 
A extends A
    ? Combination<A, AllCombinations<Exclude<B, A>>>
    : never;
type all = AllCombinations<'A' | 'B' | 'C'>;

Remember the special type

  1. IsEqual
type IsEqual<A,B> = (<T>()=>T extends A ? 1 : 2) extends (<T>()=>T extends B ? 1 : 2) ? true : false
  1. Special cases for several condition types
  • When the joint type is used as a type parameter on the left side of the conditional type, each type will be passed in separately for calculation, and the results will be combined into a joint type.
type Test<T> = T extends number ? 1 : 2;
type res = Test<1 | 'a'>;//type res = 1 | 2
  • boolean is also a union type, which is false|true.
type Test<T> = T extends true ? 1 : 2;
type res = Test<boolean>;//type res = false | true
  • If the any type is on the left side of the conditional type, it returns the union type of trueType and falseType.
type Test<T> = T extends true ? 1 : 2;
type res = Test<any>;//type res = 1 | 2
  • When the left side of the condition type is never, return never directly.
type Test<T> = T extends true ? 1 : 2;
type res = Test<never>;//type res = never

built-in advanced types

  1. Parameters - the type used to extract function parameters
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : any;
  1. ResultType - used to extract the return value type of the function
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
  1. ConstructorParameters - used to extract the parameter type of the constructor
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
  1. InstanceType - used to extract the return value type of the constructor
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
  1. Partial - turns the indexed type into an optional type
type Partial<T> = {
    
    
    [P in keyof T]?: T[P];
};
  1. Required - turns an optional index type into a required type
type Required<T> = {
    
    
    [P in keyof T]-?: T[P];
};
  1. Readonly - Change the index type into a read-only type
type Readonly<T> = {
    
    
    readonly [P in keyof T]: T[P];
};
  1. Pick - modify and filter the index, and keep the corresponding index
type Pick<T, K extends keyof T> = {
    
    
    [P in K]: T[P];
};
  1. Record - used to create index types
type Record<K extends keyof any, T> = {
    
    
    [P in K]: T;
};
  1. Exclude - used to remove part of the union type
type Exclude<T, U> = T extends U ? never : T;
  1. Extract - used to retain part of the union type
type Extract<T, U> = T extends U ? T : never;
  1. Omit - the opposite of Pick, remove the corresponding index
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
  1. Awaited - the type of ValueType used to get the Promise
type Awaited<T> =
    T extends null | undefined
        ? T 
        : T extends object & {
    
     then(onfulfilled: infer F): any }
            ? F extends ((value: infer V, ...args: any) => any)
                ? Awaited<V>
                : never 
            : T;
  1. NonNullable - used to determine whether it is a non-null type
type NonNullable<T> = T extends null | undefined ? never : T;
  1. ThisParameterType-This can be called in the function, and the type of this this can also be constrained.
type ThisParameterType<T> = 
    T extends (this: infer U, ...args: any[]) => any 
        ? U 
        : unknown;
  1. OmitThisParameter - used to extract this
type OmitThisParameter<T> = 
    unknown extends ThisParameterType<T> 
        ? T 
        : T extends (...args: infer A) => infer R 
            ? (...args: A) => R 
            : T;

Guess you like

Origin blog.csdn.net/qq_51965698/article/details/129437094