利用模板字面量类型通过笛卡尔积生成联合类型,并用 infer 解析字符串字面量。
在 Kodokon 中打开本课模板字面量类型把模板字面量语法带入了类型的世界。插入一个联合类型,编译器就会计算笛卡尔积:每一种可能的组合都会成为结果的一个成员。这是让你能精确到具体字符地为事件键、路由或设计系统的 token 建立类型的工具。
type Lang = "fr" | "en";
type Theme = "light" | "dark";
type ThemeKey = `${Lang}-${Theme}`;
// "fr-light" | "fr-dark" | "en-light" | "en-dark"真正的威力在与 infer 结合时显现:模板字面量类型变成了针对字符串的匹配模式。编译器会切分输入的字面量以匹配每个片段;当存在多种切分方式时,分隔符的第一次出现获胜。加上递归,你就得到了在编译期求值的真正的解析器。
type Split<S extends string, Sep extends string> =
S extends `${infer Head}${Sep}${infer Rest}`
? [Head, ...Split<Rest, Sep>]
: [S];
type Parts = Split<"a.b.c", ".">;
// ["a", "b", "c"]这种模式在提取 Express 风格路由的参数时大放异彩。每次递归调用消费一个 :param 片段,最终的联合类型列出每个参数名,你随后可以把它喂给 Record 来为处理器的签名建立类型。
type Params<Path extends string> =
Path extends `${string}:${infer P}/${infer Rest}`
? P | Params<Rest>
: Path extends `${string}:${infer P}`
? P
: never;
type RouteParams = Params<"/users/:id/posts/:postId">;
// "id" | "postId"TypeScript 提供了四个内建(intrinsic)工具类型 - Uppercase、Lowercase、Capitalize、Uncapitalize - 它们直接在编译器内部实现(通过 intrinsic 关键字),所以你无法自己重写它们。另一个生产模式:string & {}。在联合类型中,string 会吸收掉那些字面量,编辑器也会失去自动补全;与 {} 求交叉会创建一个等价但不同的类型,编译器不会将其化简。
type Method = "get" | "post";
type Handler = `on${Capitalize<Method>}`;
// "onGet" | "onPost"
type KnownColor = "red" | "green" | "blue";
type Color = KnownColor | (string & {});
declare function paint(color: Color): void;
paint("red"); // suggested by autocompletion
paint("#ff8800"); // also acceptedA 有 3 个成员,B 有 4 个,那么 ${A}-${B} 包含多少个成员?Capitalize 产生什么?KnownColor | (string & {}) 而不是 KnownColor | string?