Subject address: Github

Online editor: TypeScript Playground

1. ReturnType

type MyReturnType<Fn extends Function> = Fn extends(... args:any) => infer R ? R : never;
Copy the code

2. Omit

type MyExclude<T, K> = T extends K ? never : T;
type MyOmit<T, K extends keyof T> = {
  [P in MyExclude<keyof T, K>]: T[P];
}
Copy the code

3. Readonly2

Allows you to select the specified key for readonly

type MyReadonly2<T, K extends keyof T> = {
  readonly [P in K]: T[P];
} & {
  [P in MyExclude<keyof T, K>]: T[P];
}
Copy the code

4. DeepReadonly

Readonly nested properties as well

type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends number | string | symbol ? T[P] : DeepReadonly<T[P]>;
}
Copy the code

Types can also be recursive

5. TupleToUnion

type TupleToUnion<A extends any[]> = A[number] 
Copy the code

6. Chainable

Implementation can be called chain type structure, including option(key, value) get() two methods, the parameters of option is the property and value of the object, get used to get the final result.

The main thing is to implement type declarations that do this without writing logic

interface Chainable<T = {}> {
  // 'K extends String' Narrows the 'key' type to a literal type when it is derived by TS
  // '[P in K]' is used to derive 'K' as a union type, and then use 'in' to get the specific type, used as
  // the key name, so that the final type has an explicit key name
  option: <K extends string, V>(key: K, value: V) => Chainable<T & {
    [P in K]: typeof value
  }>,
  get: () => T
}
Copy the code

Being able to call chained means that the option method returns this type, so we need to provide a generic parameter T that does this: 1. Receives the key value passed by repeated calls to option and constructs a new type to continue as the next T; 2. Return value as get method.

7. Last

Gets the type of the last value of the array

type Last<A extends any[] = > [undefined. A][A['length']].Copy the code

I didn’t get it. I didn’t turn it around. The clever idea is to add an element to the front of the array, so that the original length is the last index of the new array

8. Pop

Implement the pop method of the array, return the array type after the POP

type Pop<A extends any[]> = A extends [...infer R, infer L] ? R : undefined;
type Shift<A extends any[]> = A extends [infer F, ...infer R] ? R : undefined;
Copy the code

The shift in the same way

Last could be used in a similar way, for example by returning L directly. It is important to note that the infer keyword must be used after extends in the condition type

9. PromiseAll

Take the type of the value returned by promise.all ()

type GetPromiseType<P> = P extends Promise<infer R> ? R : P;
type PromiseAll<P extends any[], R extends any[] = []> = P extends [infer F, ...infer Rest]
  ? PromiseAll<Rest, [GetPromiseType<F>, ...R]>
  : Promise<R>;
Copy the code

Again, recursion. I haven’t thought of any other way yet. To get the type of each item, recurse to the first element

10. LookUp

Find the correct type from the union type (there is {type: string} in the qualified type)

type LookUp<T, P> = T extends { type: P } ? T : never;
Copy the code

‘a’ | never = = = ‘a’, and any other types and | never returns to its itself

11. TrimLeft

Trim left on the string

type TrimLeft<S extends string> = S extends `${infer F}${infer R}`
  ? F extends ' '
    ? TrimLeft<R>
    : S
  : S;
Copy the code

Strings can also be deconstructed using conditional types, one character at a time. Strings can be freely deconstructed according to reasonable patterns

12. Trim

type ReverseString<
  S extends string,
  R extends string = ' '
> = S extends `${infer F}${infer Rest}`
  ? ReverseString<Rest, `${F}${R}`>
  : R;

type Trim<S extends string> = ReverseString<TrimLeft<ReverseString<TrimLeft<S>>>>
Copy the code

The idea is to trim the lefe, flip it, trim the left, and flip it back