持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
题目
从字符串中剔除指定字符。
例如:
type Butterfly = DropChar<" b u t t e r f l y ! ", " ">; // 'butterfly!'
解答
为了解决这个问题,首先需要了解什么是模板字面量类型?
模板字面量类型以字符串字面量类型为基础,可以通过联合类型扩展成多个字符串。
它们跟 JavaScript 的模板字符串是相同的语法,但是只能用在类型操作中。当使用模板字面量类型时,它会替换模板中的变量,返回一个新的字符串字面量:
type World = "world";
type Greeting = `hello ${World}`;
// type Greeting = "hello world"
使用模板字面量类型时,我们可以从字符串中推断所需的部分, 在下方的代码中我们用L和R推断字符串的左侧部分和右侧部分。它们之间的分界符是所需的字符本身,即C。
type DropChar<S, C> = S extends `${infer L}${C}${infer R}` ? never : never;
使用这样的表示方法,我们会得到一个编译错误Type ‘C’ is not assignable to type ‘string | number | bigint | boolean | null | undefined’.因此需要添加一个泛型约束去修复它。
type DropChar<S, C extends string> = S extends `${infer L}${C}${infer R}`
? never
: never;
当S的结构符合${infer L}${C}${infer R}时,即S可以赋值给${infer L}${C}${infer R},我们将C剔除,返回${L}${R}
type DropChar<S, C extends string> = S extends `${infer L}${C}${infer R}`
? `${L}${R}`
: never;
但返回的${L}${R}可能仍然含有C,因此我们需要递归地调用该类型,知道剔除所有C。
type DropChar<S, C extends string> = S extends `${infer L}${C}${infer R}`
? DropChar<`${L}${R}`, C>
: never;
当目标字符串中不含有C时,直接返回字符串本身S,这同时也是递归结束的条件。
type DropChar<S, C extends string> = S extends `${infer L}${C}${infer R}`
? DropChar<`${L}${R}`, C>
: S;