Drop Char(删除字符)
大约 3 分钟
Drop Char(删除字符)
题目
从字符串中删除指定的字符。
type Butterfly = DropChar<' b u t t e r f l y ! ', ' '> // 'butterfly!'解法
type DropChar<S extends string, C extends string> =
S extends `${infer L}${C}${infer R}`
? DropChar<`${L}${R}`, C>
: S核心思路:用模板字面量推断,每次找到并删掉一个 C,然后递归处理,直到字符串中不再含有 C 为止。
逐步拆解
第一步 — 模板字面量模式匹配
S extends `${infer L}${C}${infer R}`TypeScript 会尝试把 S 拆成三段:
L—C第一次出现之前的所有字符C— 要删除的字符(字面量匹配)R—C之后的所有字符
只要 C 出现在 S 中,这个条件就成立,我们就能拿到 L 和 R。
第二步 — 去掉 C 后递归
? DropChar<`${L}${R}`, C>把 L 和 R 拼回去,跳过 C,再递归处理下一个出现的 C。
第三步 — 终止条件
: S当 S 中找不到 C 时,extends 检查失败,直接返回 S。
执行轨迹示例
DropChar<' b u t ', ' '>
→ '' + 'b u t ' → DropChar<'b u t ', ' '>
→ 'b' + 'u t ' → DropChar<'bu t ', ' '>
→ 'bu' + 't ' → DropChar<'but ', ' '>
→ 'but' + '' → DropChar<'but', ' '>
→ 'but'(找不到 ' ',直接返回)深入理解
为什么单字符 C 工作得很顺畅?
本题的 C 是单个字符(长度为 1 的字符串字面量)。这很关键:当 C 是单字符时,模板字面量 ${infer L}${C}${infer R} 的分割唯一且确定——TypeScript 总是从最左侧的出现开始匹配,使递归行为完全可预测。
如果 C 是多字符子串,同样的模式也能处理,这正是更难的姊妹题 Drop String (2059-hard) 探索的方向(那道题中 C 是多个字符的联合类型)。
模板字面量类型 = 字符串的模式匹配
TypeScript 的模板字面量推断(${infer X})本质上是对字符串类型做结构化模式匹配。几点要注意:
- 左起贪心 —
${infer L}${C}${infer R}中,L尽可能短(匹配最左侧的C)。 - 精确字面量匹配 —
${C}匹配C的精确字符串值。C = ' '时,TypeScript 就找字面量空格。 - 支持递归 — 条件类型本身可以递归,因此可以遍历整个字符串。
另一种写法:逐字符处理
也可以一次只处理一个字符,逻辑更直观:
type DropChar<S extends string, C extends string> =
S extends `${infer Head}${infer Tail}`
? Head extends C
? DropChar<Tail, C>
: `${Head}${DropChar<Tail, C>}`
: S每次推断出第一个字符 Head:若等于 C 就跳过,否则保留。这种写法更啰嗦,但对"字符逐个处理"的逻辑更显式。
实际中推荐用双 infer 版本,更简洁。
与其他字符串操作题的关系
| 题目 | 技术要点 |
|---|---|
TrimLeft (106) | 删除开头空白:${' ' | '\n' | '\t'}${infer R} |
Trim (108) | 同时删两端 |
Replace (116) | 替换第一个出现 |
ReplaceAll (119) | 替换所有出现(和 DropChar 同一递归模式) |
DropChar (2070) | 删除所有指定字符 |
DropString (2059-hard) | 删除字符集合中的所有字符 |
DropChar<S, C> 本质上就是 ReplaceAll<S, C, ''>——把每个 C 替换成空字符串。
TypeScript 递归深度限制
TypeScript 的条件类型递归有深度上限(大约 1000 次实例化)。对于极长的字符串,理论上会超出限制。但实际项目中字符串长度远不到这个量级,完全不用担心。
核心要点
- 模板字面量 + 双
infer是在类型层面搜索和操作子字符串的惯用写法 - 递归实现"删除所有出现"的行为——每次递归调用删掉一个
- 终止条件是隐式的:
extends匹配失败时自然返回S DropChar<S, C>等价于ReplaceAll<S, C, ''>,理解两者能强化对这个模式的认识- 这个模式可以扩展到更难的题(如
DropString):将C改为字符联合类型即可
