Fill
挑战
Fill, a common JavaScript function, now let us implement it with types. Fill<T, N, Start?, End?>, as you can see,Fill accepts four types of parameters, of which T and N are required parameters, and Start and End are optional parameters. The requirements for these parameters are: T must be a tuple, N can be any type of value, Start and End must be integers greater than or equal to 0.
type exp = Fill<[1, 2, 3], 0> // expected to be [0, 0, 0]
In order to simulate the real function, the test may contain some boundary conditions, I hope you can enjoy it :)
解答
解答跟着我的思路一步步来,最后解出最终答案
初始状态:
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
> = any
我们需要用T extends去遍历整个数组
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
> =
T extends [infer L,...infer R]
? never
: never
一开始的思路是我们需要有一个 A 元组来传递我们每一步的结果,然后靠A['length']来判断 Start 和 End 的边缘状态,大概像下面这样
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
A extends unknown[] = []
> =
T extends [infer L,...infer R]
? A['length'] extends Start
? never
: A['length'] extends End
? never
: never
: A
但是这样显然不够,因为我们只知道A['length']刚好等于 Start 和 End的情况,所以我们需要有一个 boolean 的 In 来判断我们是否在Start和End内,如果是在内,那么我们只需要判断End,除此之外,我们只需要判断Start
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
In extends boolean = false,
A extends unknown[] = []
> =
T extends [infer L,...infer R]
?
In extends true
? A['length'] extends End
? never
: never
: A['length'] extends Start
? never
: never
: A
然后考虑
在内的时候我们要压入的是N,在外我们要压入L
以及过边缘In的状态转换
就写出了能通过大部分样例的版本
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
In extends boolean = false,
A extends unknown[] = []
> =
T extends [infer L,...infer R]
?
In extends true
? A['length'] extends End
? Fill<R,N,Start,End,false,[...A,L]>
: Fill<R,N,Start,End,true,[...A,N]>
: A['length'] extends Start
? Fill<R,N,Start,End,true,[...A,N]>
: Fill<R,N,Start,End,false,[...A,L]>
: A
但是我们发现样例里当Start和End相等时,是不做替换的
所以加入Start extends End的判断就做出了我们的最终版本:
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
In extends boolean = false,
A extends unknown[] = []
> =
Start extends End
? T
: T extends [infer L,...infer R]
?
In extends true
? A['length'] extends End
? Fill<R,N,Start,End,false,[...A,L]>
: Fill<R,N,Start,End,true,[...A,N]>
: A['length'] extends Start
? Fill<R,N,Start,End,true,[...A,N]>
: Fill<R,N,Start,End,false,[...A,L]>
: A