The best way to solve the TS problem is to practice more. This time, the difficulty of interpreting type-challenges Medium is 57~62 questions.
intensive reading
Trim Right
Implementation TrimRight
remove the space on the right:
type Trimed = TrimRight<' Hello World '> // expected to be ' Hello World'
Use infer
to find the string before the space recursively:
type TrimRight<S extends string> = S extends `${infer R}${' '}`
? TrimRight<R>
: S
Then add the boundary conditions of the test case, \n
and \t
is the complete answer:
// 本题答案
type TrimRight<S extends string> = S extends `${infer R}${' ' | '\n' | '\t'}`
? TrimRight<R>
: S
Without
Implements Without<T, U>
, removes elements U
6b1a633641b7a6a43d1f682f48071c9f--- from array T
:
type Res = Without<[1, 2], 1> // expected to be [2]
type Res1 = Without<[1, 2, 4, 1, 5], [1, 2]> // expected to be [4, 5]
type Res2 = Without<[2, 3, 2, 3, 2, 3, 2, 3], [2, 3]> // expected to be []
The most difficult point of this question is that the parameter U
may be a string or an array of strings. We can only use extends
to judge whether it exists, so there are two problems:
- How to judge whether it is both a string and an array, judged together or judged separately?
-
[1] extends [1, 2]
is false, how to judge the array mode?
This problem can be solved by converting the array to Union:
type ToUnion<T> = T extends any[] ? T[number] : T
In this way, whether it is a number or an array, it will be converted into a union type, and the union type is very convenient to judge extends
includes the relationship:
// 本题答案
type Without<T, U> = T extends [infer H, ...infer R]
? H extends ToUnion<U>
? Without<R, U>
: [H, ...Without<R, U>]
: []
Each time the first item of the array is taken, it is judged whether it is included by U
, and if so, it is discarded (the action of discarding is to discard H
and continue the recursion), otherwise it is included (the action of inclusion is to form new array [H, ...]
and deconstruct the recursive content to the back).
Trunc
Implement Math.trunc
a function of the same function Trunc
:
type A = Trunc<12.34> // 12
If the input parameter is a string, it is very simple:
type Trunc<T> = T extends `${infer H}.${infer R}` ? H : ''
If it's not a string, just convert it to a string:
// 本题答案
type Trunc<T extends string | number> = `${T}` extends `${infer H}.${infer R}`
? H
: `${T}`
IndexOf
Implement IndexOf
find the subscript where the element is located, but can't find it and return -1
:
type Res = IndexOf<[1, 2, 3], 2>; // expected to be 1
type Res1 = IndexOf<[2,6, 3,8,4,1,7, 3,9], 3>; // expected to be 2
type Res2 = IndexOf<[0, 0, 0], 2>; // expected to be -1
You need to use an auxiliary variable to store the hit index, and determine whether it matches one by one in a recursive way:
type IndexOf<T, U, Index extends any[] = []> =
T extends [infer F, ...infer R]
? F extends U
? Index['length']
: IndexOf<R, U, [...Index, 0]>
: -1
But it did not pass the test case IndexOf<[string, 1, number, 'a'], number>
, the reason is that the result of 1 extends number
is true, so we have to replace it with Equal
function to judge the equality:
// 本题答案
type IndexOf<T, U, Index extends any[] = []> =
T extends [infer F, ...infer R]
? Equal<F, U> extends true
? Index['length']
: IndexOf<R, U, [...Index, 0]>
: -1
Join
Implement TS version Join<T, P>
:
type Res = Join<["a", "p", "p", "l", "e"], "-">; // expected to be 'a-p-p-l-e'
type Res1 = Join<["Hello", "World"], " ">; // expected to be 'Hello World'
type Res2 = Join<["2", "2", "2"], 1>; // expected to be '21212'
type Res3 = Join<["o"], "u">; // expected to be 'o'
Recursion T
Take the first element each time, use an auxiliary string to store the answer, and splicing it together:
// 本题答案
type Join<T, U extends string | number> =
T extends [infer F extends string, ...infer R extends string[]]
? R['length'] extends 0
? F
: `${F}${U}${Join<R, U>}`
: ''
The only thing to note is that when the last item is processed, do not add U
, it can be judged by R['length'] extends 0
.
LastIndexOf
Implementation LastIndexOf
find the last matching subscript:
type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2> // 3
type Res2 = LastIndexOf<[0, 0, 0], 2> // -1
Similar to IndexOf
, you can judge from the last subscript forward. It should be noted that we cannot use the conventional method to reduce the subscript of Index
by one, but fortunately R
length of the array can replace the current subscript:
// 本题答案
type LastIndexOf<T, U> = T extends [...infer R, infer L]
? Equal<L, U> extends true
? R['length']
: LastIndexOf<R, U>
: -1
Summarize
There are no new knowledge points in the six questions this week, and there are still 6 medium problems left. If you can feel a dull feeling after learning this, it means that you have learned very solidly.
The discussion address is: Intensive Reading "Trim Right, Without, Trunc..." Issue #433 dt-fe/weekly
If you'd like to join the discussion, click here , there are new topics every week, with a weekend or Monday release. Front-end intensive reading - help you filter reliable content.
Follow Front-end Intensive Reading WeChat Official Account
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
Copyright notice: Free to reprint - non-commercial - non-derivative - keep attribution ( Creative Commons 3.0 license )
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。