「重学TS 2.0 」TS 练习题第二十八题
Opened this issue · 15 comments
实现一个 Split
工具类型,根据给定的分隔符(Delimiter)对包含分隔符的字符串进行切割。可用于定义 String.prototype.split
方法的返回值类型。具体的使用示例如下所示:
type Item = 'semlinker,lolo,kakuqo';
type Split<
S extends string,
Delimiter extends string,
> = // 你的实现代码
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
请在下面评论你的答案。
type Item = 'semlinker,lolo,kakuqo';
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}` ? [A,...Split<B,Delimiter>] : [S];
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
type Item = "semlinker,lolo,kakuqo";
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer First}${Delimiter}${infer Rest}` ? [First, ...Split<Rest, Delimiter>] : [S];
type ElementType = Split<Item, ",">; // ["semlinker", "lolo", "kakuqo"]
和 29 题一样
type Split<
S extends string,
Delimiter extends string,
R extends any[] = [] // 记录遍历记录
> =
S extends `${infer R1}${Delimiter}${infer R2}`
? Split<R2, Delimiter, [...R, R1]> // 记录R1, 继续遍历剩余部分
: [...R, S] // 没有更多的 Delimiter 了, 直接记录当前的 S 并返回
type ElementType1 = Split<'semlinker,lolo,kakuqo', ','>; // ["semlinker", "lolo", "kakuqo"]
type ElementType2 = Split<'dog=1&cat=2&pig=34', '&'>; // ["dog=1", "cat=2", "pig=34"]
题解
这题只要会用 ${infer X}${S}${infer Y}
这种写法就很方便了,意思是将一个字符串做拆解:
type Item = 'semlinker,lolo';
type Test<
S extends string,
Delimiter extends string,
> = S extends `${infer Key}${Delimiter}${infer Rest}`
? [Key, Rest]
: [S]
type TestElement = Test<Item, ','>; // ["semlinker", "lolo"]
这边 Key
对应 "semlinker"
,Delimiter
对应 ,
,Rest
对应 "lolo"
,这个理解了,再看这题解法就比较简单了,也是使用递归:
type Item = 'semlinker,lolo,kakuqo';
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer Key}${Delimiter}${infer Rest}`
? [Key, ...Split<Rest, Delimiter>]
: [S]
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
type ElementType2 = Split<'a|b|c||d', '|'>; // ["a", "b", "c", "", "d"]
type ElementType3 = Split<'abcdef', ''>; // ["a", "b", "c", "d", "e", "f", ""]
这边细心的朋友会发现 ElementType3
的值最后多出了 ""
,因为在最后一个位置,取到的 Rest
是空字符串,所以这边我们就需要再做处理,过滤掉空字符串:
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer Key}${Delimiter}${infer Rest}`
? [Key, ...Split<Rest, Delimiter>]
: S extends '' /* 处理空字符串 */
? []
: [S]
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
type ElementType2 = Split<'a|b|c||d', '|'>; // ["a", "b", "c", "", "d"]
type ElementType3 = Split<'abcdef', ''>; // ["a", "b", "c", "d", "e", "f"]
这样就能去掉最后一个 ""
了。
type Item = 'semlinker,lolo,kakuqo';
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}`
? [A, ...Split<B, Delimiter>]
: [S];
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"
知识点: ts 映射类型里可以使用js里的模板变量的语法,用法和含义都相同
思路: 熟练掌握 extends 配合 infer的用法
type ElementType3 = Split<'abcdef',
Split<'a,b,', ','> 这个期望结果是否符合预期
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}` ? [A, ...Split<B, Delimiter>] : [S]
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer L}${Delimiter}${infer R}`
? [L, ...Split<R, Delimiter>]
: [S];
type Split<S extends string, Delimiter extends string> = S extends `${infer Key}${Delimiter}${infer Rest}`
? [Key, ...Split3<Rest, Delimiter>]
: S extends ''
? Delimiter extends ''
? []
: [S]
: [S];
type A3 = Split3<'', ''> // []
type B3 = Split3<'o', ''> // ['o']
type C3 = Split3<'o', 'o'> // ['','']
const strDome = 'semlinker,lolo,kakuqo,ahhah'
type Item = typeof strDome;
type Split<
S extends string,
Delimiter extends string,
> = S extends ${infer A},${infer B}
? [A, ...Split<B, Delimiter>] : [S]
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
const reuslt: Split<Item, ','> = String.prototype.split.call(strDome, ',')
type Item = 'semlinker,lolo,kakuqo';
type ElementType = Split<Item, ','>; // ["semlinker", "lolo", "kakuqo"]
type Split<
S extends string,
Delimiter extends string,
> =
S extends `${infer Left}${Delimiter}${infer Right}`
? [Left, ...Split<Right, Delimiter>]
: [S]
type Split<
S extends string,
Delimiter extends string,
Arr extends string[] = []
> =
S extends `${infer Left}${Delimiter}${infer Right}`
? Split<Right, Delimiter, [...Arr, Left]>
: [...Arr, S]
type Split<
S extends string,
Delimiter extends string,
TEMP extends string[] = []
> = S extends ${infer First}${Delimiter}${infer Rest}
? Split<Rest, Delimiter, [...TEMP, First]>
: S extends ''
? TEMP : [...TEMP, S]
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}` ? [A, ...Split<B, Delimiter>] : [S]
type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer Rest}`
? [A, ...Split<Rest, Delimiter>]
: [S];