ใช้ประโยชน์จาก template literal type เพื่อสร้าง union ผ่าน Cartesian product และแยกวิเคราะห์ string literal ด้วย infer
เปิดบทเรียนนี้ใน KodokonTemplate literal type นำไวยากรณ์ template literal เข้าสู่โลกของ type การแทรก (interpolate) union เข้าไป คอมไพเลอร์จะคำนวณ Cartesian product: ทุกการผสมที่เป็นไปได้กลายเป็นสมาชิกหนึ่งของผลลัพธ์ นี่คือเครื่องมือที่ให้คุณกำหนด type ให้กับ event key, route หรือ token ของ design system ได้ลงลึกถึงตัวอักษรที่แน่นอน
type Lang = "fr" | "en";
type Theme = "light" | "dark";
type ThemeKey = `${Lang}-${Theme}`;
// "fr-light" | "fr-dark" | "en-light" | "en-dark"พลังที่แท้จริงปรากฏออกมาเมื่อรวมกับ infer: template literal type กลายเป็น รูปแบบการจับคู่ (matching pattern) บนสตริง คอมไพเลอร์ตัดแบ่ง input literal เพื่อจับคู่แต่ละส่วน; เมื่อการแบ่งเป็นไปได้หลายทาง การปรากฏครั้งแรก ของตัวคั่นจะชนะ เพิ่ม recursion เข้าไปแล้วคุณจะได้ตัวแยกวิเคราะห์ (parser) ที่แท้จริงซึ่งประเมิน ณ เวลาคอมไพล์
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"]รูปแบบนี้เปล่งประกายเมื่อสกัดพารามิเตอร์ของ route สไตล์ Express การเรียก recursive แต่ละครั้งกิน :param หนึ่งส่วน และ union สุดท้ายจะแสดงรายชื่อพารามิเตอร์ทุกตัว ซึ่งคุณสามารถป้อนเข้าไปใน Record เพื่อกำหนด type ให้กับ signature ของ handler ได้
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 - ที่ implement โดยตรงภายในคอมไพเลอร์ (คีย์เวิร์ด intrinsic) จึงเขียนใหม่เองไม่ได้ อีกหนึ่งรูปแบบสำหรับ production: string & {} ใน union นั้น string จะดูดกลืน literal และ editor จะสูญเสียการเติมข้อความอัตโนมัติ; การทำ intersect กับ {} สร้าง type ที่สมมูลแต่แตกต่างซึ่งคอมไพเลอร์ไม่ลดทอน
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 ผลิตอะไรเมื่อนำไปใช้กับ literal "hello world"?KnownColor | (string & {}) แทนที่จะเป็น KnownColor | string?