1
头图

TypeScript type gymnastics, the core idea is to generate new types from types!

Record the simple problem solutions of type-challenges, as well as the problem-solving ideas.

Warehouse address: https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md

Blog post address: https://github.com/FrankKai/FrankKai.github.io/issues/262

4 - Implement Pick

keyof / extends / in

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

Problem solving ideas

Where <T, K extends keyof T>: K is a public type, meaning that the K type is a subset of the result of keyof T. This will ensure that the type of the second parameter of Pick is not the type of the first parameter, and an error will be reported.

For example, the following code passes a 'invalid' that does not exist on the Todo type, ts will prompt an error "Type '"invalid"' is not assignable to type 'keyof Todo'."

 // @ts-expect-error
type newType = MyPick<Todo, 'title' | 'completed' | 'invalid'>

interface Todo {
  title: string
  description: string
  completed: boolean
}

https://github.com/type-challenges/type-challenges/issues/11021

7 - Implement Readonly

readonly

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

Problem solving ideas

Add readonly before the property name to achieve read-only.

key part: use keyof T to get the key set of T, then use P in to traverse, and add readonly flag to each attribute name.

value part: T[P], reuse the original type.

https://github.com/type-challenges/type-challenges/issues/11104

11 - tuple to object

extends / readonly / in / T[number]

 type TupleToObject<T extends readonly any[]> = { [P in T[number]: P }

Problem solving ideas

The point is "how to traverse each item in the tuple?", you can get each item through the number index, that is, T[number].

Why do T extends readonly any[], this is because an array of any type is passed in, and T[] is illegal, so you need to use extends to construct a new type.

https://github.com/type-challenges/type-challenges/issues/11105

14 - first element

extends / never / T[0]

 type First<T extends any[]> = T extends [] ? never : T[0];

Analysis ideas

The first item can be represented by T[0].

There is one use case to be aware of: when the array is empty, the first item is represented as never.

The point is how to judge the empty array? There are 2 ways: T extends [] , T["length"] extends 0 .

https://github.com/type-challenges/type-challenges/issues/11107

18 - Get tuple length

extends / readonly / T['length']

 type Length<T extends readonly any[]> = T['length']

Problem solving ideas

The length can be returned via T['length'].

But the premise is to construct a new type, T extends any[]

Since the tuple type is read-only, T extends readonly any[]

Consistent with the idea of 11. tuple to object

https://github.com/type-challenges/type-challenges/issues/11109

43 - Exclude

extends / never

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

Problem solving ideas

The point is how to remove U. If an item in T is in U (T extends U), return never to remove U, otherwise return T.

https://github.com/type-challenges/type-challenges/issues/11111

189-Awaited #11747

infer / 递归 / Promise<T>

 type MyAwaited<T> = T extends Promise<infer P> 
  ? P extends Promise<any>
    ? MyAwaited<P>
    : P
  : never;

Problem solving ideas

infer + recursion + Promise<T>

For common types, such as type X = Promise<string>, use T extends Promise<infer P> to determine.
But for nested types, such as type Z = Promise<Promise<string | number>>, it is necessary to judge whether P is a Promise type, and if so, recursively judge.

https://github.com/type-challenges/type-challenges/issues/11747

268 - If

extends boolean / extends true

 if<C extends boolean, T, F> = C extends true ? T : F

Problem solving ideas

How to constrain generic to boolean type? C extends boolean.

How to judge the current generic type is true? C extends true.

https://github.com/type-challenges/type-challenges/issues/11404

533-Concat

...T 解构

 type Contact<T extends any[], U extends any[]> = [...T, ...U]

Problem solving ideas

Array type input parameter: T extends any[]

Generic destructuring (core: destructing generic variables via ...): [...T, ...U]

https://github.com/type-challenges/type-challenges/issues/11423

898 - Includes

infer / ...T 解构 / 递归

 type MyEqual<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false

type Includes<T extends readonly any[], U> = T extends [infer P, ...infer Rest] 
  ? MyEqual<P, U> extends true 
    ? true
    : Includes<Rest, U>
  : false;

Problem solving ideas

Destructuring + infer + recursion

Judgment method: recursively take the first item in T and U to judge whether they are equal.

Need to implement an Equal function, you can use https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 in the official discussion

https://github.com/type-challenges/type-challenges/issues/11534

3057-Push

...T 解构

 type Push<T extends any[], U> = [...T, U]

Problem solving ideas

Constraining array type variables: T extends any[]

Type variable destructuring: ...T

https://github.com/type-challenges/type-challenges/issues/11527

3060-Unshift

...T 解构

 type Unshift<T extends any[], U> = [U, ...T]

Problem solving ideas

Constraining array type variables: T extends any[]

Type variable destructuring: ...T

https://github.com/type-challenges/type-challenges/issues/11529

3312 - Parameters

infer

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

Problem solving ideas

Use infer to represent the type variable to be inferred.

Since ... args itself is already a tuple type, what infer P eventually deduces is also a tuple type.

https://github.com/type-challenges/type-challenges/issues/11539


趁你还年轻
4.1k 声望4.1k 粉丝