TypeScipt 每日类型挑战-medium-<DropChar>

121 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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"

使用模板字面量类型时,我们可以从字符串中推断所需的部分, 在下方的代码中我们用LR推断字符串的左侧部分和右侧部分。它们之间的分界符是所需的字符本身,即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;

更多