这里主要记录一些在 type-challenges 中遇到的有意思的挑战,以及一些不熟悉的 TS 语法。
18. Length of Tuple
For given a tuple, you need create a generic
Length
, pick the length of the tuple.For example:
answer:
知识点
- 对于
readonly []
或元组类型来说,length
属性是一个数字字面量。
- 如果元组中包含可选属性,或使用了剩余元素语法,
length
属性则只会是number
。
- 元组是特殊的数组。
898.Includes
Implement the JavaScript
Array.includes
function in the type system. A type takes the two arguments. The output should be a boolean true
or false
.For example:
answer:
知识点
infer
可以在正在比较的的类型中推断类型,一般同extends
一起使用。
- 对于
Array
类型,可以使用解构语法解构。
- 如果需要使用遍历的时候,可以考虑递归。
3.Omit
Implement the built-in
Omit<T, K>
generic without using it.
Constructs a type by picking all properties from T
and then removing K
For example
answer:
知识点
- 通过 as 实现键名重新映射(Key Remapping via as )
- 一般用来用已有的属性名通过模版字面量拓展成新的属性名。
- 或者是通过条件判断返回
never
来过滤属性。 - 或者是在遍历非字符串字面量联合类型时用索引访问器取出任意值。
8. Readonly 2
Implement a generic
MyReadonly2<T, K>
which takes two type argument T
and K
.K
specify the set of properties of T
that should set to Readonly. When K
is not provided, it should make all properties readonly just like the normal Readonly<T>
.For example:
answer:
知识点
- 当需要重复遍历才能解决时,考虑交集类型。
- 使用
=
可以给泛型参数设置默认值。
9. Deep Readonly
Implement a generic
DeepReadonly<T>
which make every parameter of an object - and its sub-objects recursively - readonly.You can assume that we are only dealing with Objects in this challenge. Arrays, Functions, Classes and so on do not need to be taken into consideration. However, you can still challenge yourself by covering as many different cases as possible.
For example:
answer:
知识点
- 深度遍历时,判断是否已经到最底层的依据是
keyof T[K] extends never
。
10. Tuple to Union
Implement a generic
TupleToUnion<T>
which covers the values of a tuple to its values union.For example:
answer:
知识点
- 数组是使用索引签名定义的对象,所以通过索引访问
number
就能获取所有值的类型,而元组的成员的数量固定且成员类型为字符串字面量。(猪脑子啊一直记不住)
12.Chainable Options
Chainable options are commonly used in Javascript. But when we switch to TypeScript, can you properly type it?
In this challenge, you need to type an object or a class - whatever you like - to provide two function
option(key, value)
and get()
. In option
, you can extend the current config type by the given key and value. We should about to access the final result via get
.For example:
answer:
知识点
- 使用 泛型
T
来保存了当前对象的类型,设置了默认值,并在接下来的重复调用中替换为上一次调用的结果的类型。
- 题目要求在
key
相同时,当类型改变时才能改变对象的值,所以第3 - 5 行判断了T
中已有的值和value
的类型来收束了key
的类型。
- 由于
K
已经是被收束后的类型,所以使用Omit
工具类型来排除T
中重复的类型。
[Key in K]
在索引签名中使用映射类型可以将 字符串字面量联合类型设置为类型的属性。
参考
20. Promise.all
Type the function
PromiseAll
that accepts an array of PromiseLike objects, the returning value should be Promise<T>
where T
is the resolved result array.for example:
answer:
知识点
- 定义泛型参数为
readonly
数组,readonly [...T]
。
- 数组类型是特殊的对象类型。
106. Trim Left
Implement
TrimLeft<T>
which takes an exact string type and returns a new string with the whitespace beginning removed.For example:
answer:
知识点
- 字面量模版类型中如果存在一个变量是联合类型,那么则会采用分配律。
- 使用
infer
可以从正在进行条件判断的类型中推断出类型。
110.Capitalize
Implement
Capitalize<T>
which converts the first letter of a string to uppercase and leave the rest as-is.For example
answer
知识点
- 对字面量使用
infer
, 第一个被推断出来的将是第一个字母组成的字符串字面量类型或是我们的泛型变量的前面一部分,最后一个推断类型是剩余的字符串字面量类型。
Uppercase
工具类型将所有的字母转换为大写。
191.Append Argument
For given function type
Fn
, and any type A
(any in this context means we don't restrict the type, and I don't have in mind any type 😉) create a generic type which will take Fn
as the first argument, A
as the second, and will produce function type G
which will be the same as Fn
but with appended argument A
as a last one.For example,
answer
知识点
- 定义函数参数和返回值为任意:
(...args: any[])=>unknown
- 使用
infer
推断函数的参数类型和返回值类型:Fn extends (...args: infer P)=> infer R