模板字面量类型
本教程共 80 篇 · 第 48 篇 · 更新于 2026-08-10 · 约 10 分钟阅读
本节目标:学会用模板字面量类型在类型层面拼接字符串,利用联合类型的自动展开生成精确的字符串联合,以及用内置的 Uppercase/Lowercase 等工具类型处理大小写。
类型里的字符串拼接
JavaScript 有模板字符串 `Hello ${name}`,TypeScript 把同样的能力搬到了类型系统里:
type World = "world";
type Greeting = `Hello ${World}`; // "Hello world"
Greeting 的类型不是 string,而是精确的字面量 "Hello world"。这和 JavaScript 的模板字符串直觉一致,只是它发生在编译期的类型层面。
为什么要这东西
实际开发中,有很多字符串是有固定格式的:onClick、getUsers、btn-primary-lg。用 string 类型太宽泛,用字面量手动拼太麻烦。模板字面量类型解决的正是这个痛点——用规则生成精确的字符串类型。
联合类型的笛卡尔积
这是模板字面量类型最神奇的行为:当插值位置是一个联合类型时,TypeScript 会自动生成所有可能的组合:
type Size = "sm" | "md" | "lg";
type Variant = "primary" | "secondary";
// 自动展开为 3 × 2 = 6 种组合
type BtnClass = `btn-${Variant}-${Size}`;
// "btn-primary-sm" | "btn-primary-md" | "btn-primary-lg"
// | "btn-secondary-sm" | "btn-secondary-md" | "btn-secondary-lg"
每个联合成员都和其他联合成员各组合一次——这就是笛卡尔积。TypeScript 替你算好了所有可能的字符串,你只需要关心结果就行。
不过有个提醒:联合成员太多会导致类型膨胀。比如两个各有 10 个成员的联合组合,生成 100 种字面量——编辑器可能会卡。
内置字符串操作类型
TypeScript 提供了四个内置的”字符串方法”,但它们在类型层面运行,不产生运行时开销:
| 类型 | 作用 | 示例 |
|---|---|---|
Uppercase<T> | 全大写 | Uppercase<"hello"> → "HELLO" |
Lowercase<T> | 全小写 | Lowercase<"HELLO"> → "hello" |
Capitalize<T> | 首字母大写 | Capitalize<"hello"> → "Hello" |
Uncapitalize<T> | 首字母小写 | Uncapitalize<"Hello"> → "hello" |
这些工具类型只接受 string 的子类型,不能用于 number 或 boolean。
实际用法
事件名生成
前端框架里到处都是 onClick、onSubmit、onChange 这种事件名。用模板字面量类型可以保证事件名格式统一:
type EventName = "click" | "submit" | "change" | "focus";
// 自动生成 on 开头的事件类型
type Handler = `on${Capitalize<EventName>}`;
// "onClick" | "onSubmit" | "onChange" | "onFocus"
如果有人写了 "onclick"(小写 c),TypeScript 会直接报错——省了一个 ESLint 规则。
API 路径类型
type HttpMethod = "get" | "post" | "put" | "delete";
type Resource = "users" | "posts" | "comments";
// 自动生成所有 API 端点
type Endpoint = `/${HttpMethod}/${Resource}`;
// "/get/users" | "/get/posts" | ... 共 12 种组合
虽然实际项目不会把所有端点列成一个联合类型,但这个模式展示了模板字面量类型的精确表达能力。
自定义工具类型
// 给任意字符串加前缀
type Prefixed<T extends string, P extends string> = `${P}${Capitalize<T>}`;
type Action = Prefixed<"save", "on">; // "onSave"
type Action2 = Prefixed<"delete", "handle">; // "handleDelete"
与 infer 的预告
模板字面量类型和 infer 配合可以实现类型层面的字符串匹配和解析,比如用 `${infer First}-${infer Last}` 从联合类型中拆分字符串。下一章 infer 会详细讲这个。
小结
`${A}${B}`在类型层面拼接字符串,结果是精确的字面量类型- 联合类型做插值时会自动展开成笛卡尔积——注意成员多的场景
Uppercase/Lowercase/Capitalize/Uncapitalize是类型层的字符串操作- 适用于事件名、API 路径、CSS 类名等有固定格式的字符串场景