TypeScript类型体操,核心思想是 通过类型生成新的类型!
记录一下type-challenges的简单题题解,以及解题思路。
仓库地址:https://github.com/type-chall...
博文地址:https://github.com/FrankKai/F...
4 - 实现 Pick
keyof / extends / in
type MyPick = { [P in K] : T[P]}
解题思路
其中的
比如,下面代码传了一个在Todo类型上不存在的'invalid',ts会提示报错” Type '"invalid"' is not assignable to type 'keyof Todo'.“
// @ts-expect-error
type newType = MyPick
interface Todo {
title: string
description: string
completed: boolean
}
https://github.com/type-chall...
7 - 实现 Readonly
readonly
type MyReadonly = { readonly [P in keyof T] : T[P] }
解题思路
在属性名前增加readonly,即可实现只读。
key部分:利用keyof T得到T的键集合,再利用P in 做遍历,并为每个属性名增加readonly标识。
value部分:T[P],复用原先的类型即可。
https://github.com/type-chall...
11 - 元组转换为对象
extends / readonly / in / T[number]
type TupleToObject = { [P in T[number]: P }
解题思路
重点是“如何遍历元祖中的每一项?”,可以通过number索引,也就是T[number]获取到每一项。
为什么要T extends readonly any[],这是因为要传入的是一个任意类型的数组,而T[]这种事不合法的,所以需要使用extends去构造一个新的类型。
https://github.com/type-chall...
14 - 第一个元素
extends / never / T[0]
type First = T extends [] ? never : T[0];
解析思路
第一项通过T[0]即可表示。
有一个用例需要注意:空数组时,第一项表示为never。
重点是 如何判断空数组?有2种办法:T extends []
,T["length"] extends 0
。
https://github.com/type-chall...
18 - 获取元组长度
extends / readonly / T['length']
type Length = T['length']
解题思路
可以通过T['length']返回长度。
但是前提是构造一个新的类型,T extends any[]
由于元组类型是只读的,所以需要T extends readonly any[]
与11.元组转对象思路一致
https://github.com/type-chall...
43 - Exclude
extends / never
type MyExclude = T extends U ? never : T
解题思路
重点是如何移除U,T中的某一项如果在U中(T extends U),返回never移除U,否则返回T。
https://github.com/type-chall...
189 - Awaited #11747
infer / 递归 / Promise
type MyAwaited = T extends Promise
? P extends Promise
? MyAwaited
: P
: never;
解题思路
infer + 递归 + Promise
对于普通的类型,例如type X = Promise
但是对于嵌套类型,例如type Z = Promise
https://github.com/type-chall...
268 - If
extends boolean / extends true
if = C extends true ? T : F
解题思路
如何约束泛型为boolean类型?C extends boolean。
如何判断当前泛型为true?C extends true。
https://github.com/type-chall...
533 - Concat
...T 解构
type Contact = [...T, ...U]
解题思路
数组类型入参:T extends any[]
泛型解构(核心:通过...解构泛型变量):[...T, ...U]
https://github.com/type-chall...
898 - Includes
infer / ...T 解构 / 递归
type MyEqual =
(() => T extends X ? 1 : 2) extends
(() => T extends Y ? 1 : 2) ? true : false
type Includes = T extends [infer P, ...infer Rest]
? MyEqual extends true
? true
: Includes
: false;
解题思路
解构+infer+递归
判断方式:递归取T中第一项与U进行判断是否相等。
需要实现一个Equal函数,可以使用官方讨论中的https://github.com/microsoft/...
https://github.com/type-chall...
3057 - Push
...T 解构
type Push = [...T, U]
解题思路
约束数组类型变量:T extends any[]
类型变量解构: ...T
https://github.com/type-chall...
3060 - Unshift
...T 解构
type Unshift = [U, ...T]
解题思路
约束数组类型变量:T extends any[]
类型变量解构: ...T
https://github.com/type-chall...
3312 - Parameters
infer
type MyParameters any> = T extends (...args: infer P) => unknown ? P : never;
解题思路
使用infer表示待推断的类型变量。
由于...args本身已经是元组类型,因此infer P最终推导出的,也是元组类型。