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