☰
type-challenges 题解:实现 TrimLeft 去除字符串左侧空白(template-literal 中等题)
2026/9/30 6:40:46 网站建设 项目流程
  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载

本篇文章围绕 type-challenges(TypeScript 类型挑战)第 106 题「去除左侧空白 / Trim Left」展开,完整讲解TrimLeft<T>类型工具的实现思路、测试边界与相关扩展。读者读完本文将掌握:如何用递归模板字面量类型在类型层面剥离字符串开头的空白字符,如何通过@type-challenges/utils的Equal断言验证结果,以及如何从本题出发组合出Trim(去除两端空白)与TrimRight(去除右侧空白)等变体。

一、题目要求

题目位于仓库的 questions/00106-medium-trimleft 目录,难度为medium(中等),标签为template-literal(模板字面量类型),由 Anthony Fu(@antfu:

difficulty: medium title: Trim Left tags: template-literal author: github: antfu name: Anthony Fu related: 108, 4803

题目描述(见 README.zh-CN.md):

实现TrimLeft<T>,它接收确定的字符串类型并返回一个新的字符串,其中新返回的字符串删除了原字符串开头的空白字符串。

题目给出的示例:

type trimmed = TrimLeft<' Hello World '> // 应推导出 'Hello World '

注意示例细节:只删除开头的空白,'Hello World'结尾的两个空格原样保留,这正是TrimLeft与Trim的区别所在。

二、从零实现:递归模板字面量类型

题目给出的起始模板只有一行占位实现(见 template.ts):

type TrimLeft<S extends string> = any

我们需要把any替换为真正的实现。核心思路是条件类型 + 模板字面量类型的模式匹配 + 递归:

  1. 用模板字面量'${Whitespace}${Rest}'匹配「一个空白字符 + 其余部分」;
  2. 匹配成功说明开头仍是空白,递归处理Rest,继续剥离下一个空白字符;
  3. 匹配失败说明开头已经不是空白(或是空字符串),直接返回S。

完整的参考实现如下:

type Whitespace = ' ' | '\n' | '\t' type TrimLeft<S extends string> = S extends `${Whitespace}${infer Rest}` ? TrimLeft<Rest> : S

验证题目示例:

type trimmed = TrimLeft<' Hello World '> // ' Hello World ' 去掉第一个空格 → ' Hello World ' // 再去掉一个空格 → 'Hello World ' // 'H' 不是空白 → 返回 'Hello World ' // 结果:'Hello World '

三、空白字符的定义:空格、换行与制表符

观察测试用例(见 test-cases.ts),题目要求的「空白」并不只指普通空格' ',还包括换行符'\n'和制表符'\t':

import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<TrimLeft<'str'>, 'str'>>, Expect<Equal<TrimLeft<' str'>, 'str'>>, Expect<Equal<TrimLeft<' str'>, 'str'>>, Expect<Equal<TrimLeft<' str '>, 'str '>>, Expect<Equal<TrimLeft<' \n\t foo bar '>, 'foo bar '>>, Expect<Equal<TrimLeft<''>, ''>>, Expect<Equal<TrimLeft<' \n\t'>, ''>>, ]

逐条解读这些断言:

输入期望输出说明
'str''str'开头无空白,原样返回
' str''str'去掉 1 个空格
' str''str'连续 5 个空格全部剥离
' str ''str '只去掉左侧 5 个空格,右侧空格保留
' \n\t foo bar ''foo bar '空格、换行、制表符混合,全部剥离
''''空字符串直接返回,递归终止
' \n\t'''全由空白组成,递归剥完,返回空字符串

正是第 5 条用例的存在,决定了Whitespace联合类型必须包含' ' | '\n' | '\t'三种字符;如果只处理空格' ','\n'与'\t'无法匹配${Whitespace}${infer Rest},实现就会在混合空白输入上失败。

四、递归终止与边界情况

TrimLeft的递归天然具备终止条件,不需要额外的显式判断:

  • 空字符串:''无法匹配`${Whitespace}${infer Rest}`模板(模板要求至少一个空白字符 + 至少一个后续字符……实际上仅要求存在空白前缀即可,空串显然不满足),走false分支返回'';
  • 开头非空白:如'str','s'不属于Whitespace联合,同样走false分支返回原字符串;
  • 全空白字符串:如' \n\t',每次剥离一个空白字符后递归,直到剩下的空串无法继续匹配,逐层返回''。

可以验证这一行为与 JavaScript 运行时方法的一致性:' \n\t'.trimStart()返回'',' \n\t foo bar '.trimStart()返回'foo bar '。TrimLeft正是String.prototype.trimStart()(以及trimLeft())在类型层面的等价物。

五、由 TrimLeft 组合出 Trim 与 TrimRight

info.yml中related: 108, 4803明确指出本题与另外两道中等题构成系列关系,它们在仓库中的位置如下:

  • 108 去除两端空白字符Trim:questions/00108-medium-trim/README.zh-CN.md,要求删除字符串两端的空白;
  • 4803 去除右侧空白TrimRight:questions/04803-medium-trim-right/README.zh-CN.md,要求只删除结尾的空白。

TrimRight的实现与TrimLeft完全对称,只是把模式匹配放到字符串尾部(对应 test-cases.ts 中的'str '、' foo bar \n\t '等用例):

type Whitespace = ' ' | '\n' | '\t' type TrimRight<S extends string> = S extends `${infer Rest}${Whitespace}` ? TrimRight<Rest> : S

而Trim既可以写成「先TrimLeft再TrimRight」的左右剥离组合,也可以一次完成两端剥离。组合式实现最简洁、复用性最好(对应 questions/00108-medium-trim/test-cases.ts 中' str '→'str'的完整剥离断言):

type Trim<S extends string> = TrimRight<TrimLeft<S>>

三题共用同一组Whitespace空白字符集合(' ' | '\n' | '\t'),构成了 type-challenges 中「模板字面量类型递归」这一主题的完整练习链:先做TrimLeft掌握左侧剥离与模式匹配,再做TrimRight掌握右侧对称写法,最后用Trim串联两个方向。此外,本仓库还有一批同样依赖模板字面量递归的同类挑战可供继续深入,例如 去除两端空白 Trim 之外的字符串处理题(如 Trim、TrimRight 系列,以及仓库中大量基于字符串拆解递归的 medium/hard 题目)。

六、总结

TrimLeft是理解 TypeScript 模板字面量类型与递归类型的关键入门题。它的要点可以归纳为三点:

  1. 模式匹配:利用`${Whitespace}${infer Rest}`在类型层面拆出「首个空白字符 + 剩余部分」,这是所有字符串处理类型工具的基础动作;
  2. 递归剥离:匹配成功时递归调用自身,逐个吃掉开头的空白,直到命中终止条件;
  3. 空白集合:空白必须定义为' ' | '\n' | '\t'的联合类型,否则无法通过换行、制表符混合的测试用例。

掌握TrimLeft之后,顺着 related: 108, 4803 继续挑战Trim与TrimRight,即可完整掌握「左右端空白剥离」这一模板字面量类型的经典主题。

  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载

相关推荐

上一篇:Pachyderm开发指南:贡献代码与扩展平台功能
下一篇:NetBox 数据模型体系完全指南:模型类型、特性矩阵与源码级基类解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询