ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入理解 TypeScript 模板联合类型(Template Union Types):在类型层面组合字符串的实战指南

深入理解 TypeScript 模板联合类型(Template Union Types):在类型层面组合字符串的实战指南 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载本文以开源仓库 The Concise TypeScript Book 法语版第 44 章「Types union de littéraux de gabarit」对应英文版 Template Union Types为骨架结合仓库内 others.md、type-manipulation.md、exploring-the-type-system.md 等章节的源码级示例系统讲解模板联合类型的语法、笛卡尔积展开机制、与映射类型/索引签名/工具类型的组合用法以及可复制的实战模式。一、模板联合类型是什么模板联合类型Template Union Types是 TypeScript 在类型层面合并与操作文本的能力。法语版文档的原话是Les types union de littéraux de gabarit peuvent servir à fusionner et à manipuler du texte au sein du système de types.翻译过来即模板联合类型可以在类型系统中合并和操作文本。它建立在模板字面量类型Template Literal Types之上——模板字面量类型允许你使用反引号和${...}占位符来构造字符串类型当占位符内部是联合类型时TypeScript 会自动展开出所有可能的字符串组合形成一个新的联合类型也就是模板联合类型。在 The Concise TypeScript Book 的章节体系中它位于 Types conditionnels prédéfinis预定义条件类型之后、Type any 之前属于类型操纵Manipulation des types链条上的关键一环——你可以从目录页看到它与其他类型工具的并列位置。二、核心语法与官方示例逐行拆解文档给出的完整示例只有一段代码但信息密度极高type Status active | inactive; type Products p1 | p2; type ProductId id-${Products}-${Status}; // id-p1-active | id-p1-inactive | id-p2-active | id-p2-inactive逐行拆解type Status active | inactive;定义了一个字符串字面量联合类型。正如仓库中 Types littéraux字面量类型 一章所解释的字面量类型是只包含单一元素的集合active | inactive就是一个只允许这两个确切字符串的联合。type Products p1 | p2;同理定义第二个取值集合。type ProductId \id-${Products}-${Status};** 是核心把两个联合类型分别放入模板字面量占位符${Products}和${Status} 中。TypeScript 会对每个占位符逐一穷举联合成员做笛卡尔积**组合最终生成 4 个精确的字符串字面量类型id-p1-activeid-p1-inactiveid-p2-activeid-p2-inactive从集合论视角看对应仓库 Exploring the Type System 中Types as Sets一节的观念Products是含 2 个元素的集合Status是含 2 个元素的集合模板联合类型ProductId就是这两个集合的笛卡尔积——共 4 个元素的字符串集合。占位符越多、联合成员越多结果呈乘法增长。验证这个类型最简单的方式是把它当作注解使用const id1: ProductId id-p1-active; // Valid const id2: ProductId id-p2-inactive; // Valid const id3: ProductId id-p1-disabled; // Error: Type id-p1-disabled is not assignable to type ProductId const id4: ProductId id-p3-active; // Error: 不在任何组合中一旦某个字符串不在笛卡尔积集合内编译器会立刻报错——这正是模板联合类型的价值把运行时才能发现的非法字符串提前到编译期拦截。三、更多占位符与任意插槽位置模板字面量类型并不仅限于两个占位符也不要求占位符在末尾。仓库法语版 others.md 的「Types littéraux de gabarit」一节给出了另一个典型示例把三个联合类型组合成一个 ID 格式type Department engineering | hr; type Language english | spanish; type Id ${Department}-${Language}-id; // engineering-english-id | engineering-spanish-id | hr-english-id | hr-spanish-id这里 2 × 2 4 个成员并且静态文本-id位于占位符之后说明占位符可以出现在模板的任意位置开头、中间、结尾甚至多个静态片段交错排列type Endpoint /api/${Department}/${Language}/v1; // 4 种组合的 URL 路径 type Full ${Department}::${Language}; // engineering::english | engineering::spanish | ...占位符内部也可以是更复杂的类型表达式例如嵌套的模板联合type Region us | eu; type Tier Region extends us ? pro : basic; // 条件类型也可以参与 type Host ${Region}-${Tier}.example.com; // us-pro.example.com | eu-basic.example.com四、为什么需要联合与字面量推断的配合模板联合类型的效果依赖一个前提占位符内的联合成员必须是字面量类型而不是宽泛的string。这与仓库 Inférence des littéraux字面量推断 一节的机制直接相关——如果类型被推断拓宽为string模板联合就会退化为string失去约束力// 对象属性会被推断为宽泛的 string可被后续修改导致模板退化为 string let product { status: active, // 推断为 string 而非 active }; type Id2 id-${typeof product.status}-${Status}; // 退化为 id-${string}-...因此当你要基于值构造模板联合时务必使用as const或显式字面量注解保住字面量类型const statuses [active, inactive] as const; // readonly [active, inactive] const products [p1, p2] as const; type StatusFromConst (typeof statuses)[number]; // active | inactive type ProductsFromConst (typeof products)[number]; // p1 | p2 type ProductId2 id-${ProductsFromConst}-${StatusFromConst}; // 与官方示例完全一致这里用到了 Indexation de type类型索引 中的下标访问语法T[number]来把只读元组转换成联合类型是实际项目中最常见的从值到模板联合的标准管道。五、模板联合 × 映射类型重映射对象键模板字面量类型最常见的进阶用法是在映射类型中通过as子句重映射remap键名。仓库 Exploring the Type System 的「Type Assertion」一节给出了一个真实示例——为对象的每个键生成带prefix_前缀的 gettertype JType { [Property in keyof Type as prefix_${string Property}]: () Type[Property]; }; type X { a: string; b: number; }; type Y JX;结果Y等价于type Y { prefix_a: () string; prefix_b: () number; };两个关键点值得展开string Property的作用keyof Type可能是string | number | symbol的联合而模板字面量占位符只接受string | number | bigint | boolean | null | undefined等可字符串化类型不能直接放入symbol。通过string Property做交集既把键收敛到字符串域又保留了精确的字面量键名这是模板重映射键的标准写法。值的变换右侧() Type[Property]通过类型索引保留了每个键的原始值类型让生成的函数返回类型与源属性一一对应。同理你可以在as子句中做大小写转换、加后缀、替换前缀构造出类似getA、setA或事件回调映射等形态。映射类型本身的机制可参考 Types mappés映射类型 一章——它遍历keyof T生成新对象而as重映射则让键名本身也能被模板字面量改造。六、模板联合 × 索引签名key-${string}模式从 TypeScript 4.4 起索引签名除了string、number、symbol还允许使用模板字面量模式作为键的类型。仓库 others.md 的「Signatures dindex avec motifs de chaînes de gabarit」一节提供了完整示例const uniqueSymbol Symbol(description); type MyKeys key-${string}; type MyObject { [uniqueSymbol]: string; [key: MyKeys]: number; }; const obj: MyObject { [uniqueSymbol]: Unique symbol key, key-a: 123, key-b: 456, }; console.log(obj[uniqueSymbol]); // Unique symbol key console.log(obj[key-a]); // 123 console.log(obj[key-b]); // 456这里MyKeys是一个模板字面量模式——它以key-开头、后缀是任意字符串。索引签名[key: MyKeys]: number意味着任何以key-开头的键都必须存number但普通键如abc则不受该签名约束也不会被允许。这比裸[key: string]: number精确得多能在不牺牲灵活性的前提下锁死命名规范。注意与模板联合类型的区分key-${string}中的${string}是通配匹配任意字符串因此是无限集合而本文主题的模板联合如${Products}-${Status}中占位符是有限联合结果是可枚举的有限字符串集合。二者同为模板字面量类型的两个方向理解这个区别可以避免滥用无限模式导致类型检查失效。七、模板联合 × 字符串工具类型大小写变换模板字面量类型与内置字符串工具类型type-manipulation.md 的「Types utilitaires」一节配合可以对生成结果的形态做二次加工。仓库文档给出的四个工具类型type MyType Uppercaseabc; // ABC type MyType LowercaseABC; // abc type MyType Capitalizeabc; // Abc type MyType UncapitalizeAbc; // abc它们可以直接嵌套在模板联合里实现先组合、再变形type Status active | inactive; type Products p1 | p2; // 生成大写枚举风格的常量名 type ConstName Uppercase${Products}_${Status}; // P1_ACTIVE | P1_INACTIVE | P2_ACTIVE | P2_INACTIVE // 生成驼峰式 getter 名 type GetterName get${Capitalize${Products}${Status}}; // getP1active | getP1inactive | getP2active | getP2inactive由于Uppercase、Capitalize等工具类型本身就是用模板字面量类型实现的在 TypeScript 的lib.es5.d.ts中以条件类型 Intrinsic内置指令形式定义它们的输入输出都是字符串字面量类型因此能无损地与模板联合组合、嵌套、传递类型层面的字符串变换流水线完全成立。八、实战模式什么时候用模板联合类型综合仓库各章节的示例模板联合类型在真实项目中常见于以下几类场景1. 领域 ID / 代码体系本文核心示例的直接落地 订单号、消息 ID、资源标识符往往由多个维度拼接而成。用模板联合把维度的合法取值枚举出来非法 ID 会在编译期直接暴露type Region cn | us | eu; type Env dev | prod; type RequestId req-${Env}-${Region}-${number}; // 注意${number} 是通配数字片段可与有限联合混用2. 事件名 / 消息类型配合联合判别discriminated unions思路 UI 库中组件 动作的事件命名非常适合模板联合配合Record或 switch 可以做穷尽性检查。3. API 路由与 RPC 方法名把资源名和操作名组合成路由或方法名前端调用时获得完整的字符串补全IntelliSense服务端按同一联合做穷尽匹配。4. CSS 类名 / 设计令牌${size}-${color}这样的类名组合能精确枚举设计系统里的合法样式组合杜绝手写类名拼写错误。5. 映射类型的键重映射见第五节 在状态机、store、表单校验等场景中从已有类型生成set_xxx、onXxx、toJSON_xxx等派生 API 面。九、局限与注意事项模板联合类型并非万能使用时有三个边界需要清楚结果数量随联合成员呈乘法爆炸。两个 10 成员的联合组合就是 100 个字符串字面量占位符越多编译器展开负担越大编辑器补全列表也会变长。对无限集合需求如任意后缀应改用key-${string}这种模板字面量模式见第六节而不是枚举。占位符不能是宽泛类型以外的一切。symbol无法直接放进占位符需先string T收敛object、null等类型是否可字符串化受 TS 版本与目标约束遇到报错时优先检查占位符类型是否可字符串化。类型只在编译期存在。模板联合类型不会生成任何运行时代码——它是纯编译期结构用于约束与补全不会改变最终 JS 产物。这与仓库 Types structurels effacés结构类型擦除 一章描述的类型擦除原则一致。十、延伸阅读模板联合类型在 The Concise TypeScript Book 中不是孤立知识点它与以下章节构成完整知识链均位于仓库website/src/content/docs/fr-fr/book/目录Types littéraux字面量类型字面量类型的集合论基础Inférence des littéraux字面量推断as const保字面量的机制Type union联合类型|运算符与联合语义Types mappés映射类型keyof 属性变换Types conditionnels prédéfinis预定义条件类型Exclude/Extract等集合操作Manipulation des types类型操纵Uppercase/Capitalize等字符串工具类型Autres其他模板字面量模式索引签名与模板字面量类型补充示例若需快速验证本文所有代码片段可直接在任意 TypeScript 工程中新建.ts文件运行tsc --noEmit或使用 IDE 的 IntelliSense 悬停查看联合类型展开结果。整个章节的知识地图可以从目录页以及英文原版 Template Union Types 出发对照 The Concise TypeScript Book 全书顺序系统学习。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐SongBloom模型进化史2025年三大版本更新亮点与功能改进解析SongBloom模型进化史2025年三大版本更新亮点与功能改进解析 SongBloom作为通过交错自回归草图和扩散优化实现连贯歌曲生成的官方代码仓库在20文档教程The Concise TypeScript Book 之模板联合类型Template Union Types实战详解The Concise TypeScript Book 之模板联合类型Template Union Types实战详解 本文以《The Concise Ty文档教程The Concise TypeScript Book模板联合类型Template Union Types完全指南The Concise TypeScript Book模板联合类型Template Union Types完全指南 模板联合类型Template Uni文档教程上一篇vue-form-generator入门教程5分钟学会创建你的第一个动态表单下一篇Redux类型安全终极方案typesafe-actions全面对比与优势分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表