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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。