สร้างแบบจำลองสถานะต่าง ๆ ของแอปพลิเคชันด้วย union ที่คอมไพเลอร์ตรวจสอบให้คุณ
เปิดบทเรียนนี้ใน Kodokonliteral type จำกัดค่าให้เป็นเนื้อหาที่แน่นอน: 'info' แทนที่จะเป็น string มันคือรากฐานของ API ที่ใช้ผิดไม่ได้: คอมไพเลอร์ปฏิเสธค่าใด ๆ ที่อยู่นอกรายการ และเอดิเตอร์ของคุณเสนอการเติมข้อความอัตโนมัติ
type Level = "info" | "warn" | "error";
function log(level: Level, message: string): void {
console.log(`[${level}] ${message}`);
}
log("info", "Server started");
// log("fatal", "Boom"); -> rejected by the compilerขั้นตอนต่อไปคือการรวม object type ที่มีคุณสมบัติ literal ร่วมกัน เรียกว่า discriminant ตัวอย่างเช่น แต่ละสถานะของการเรียกเครือข่ายจะพกพาเฉพาะข้อมูลที่เป็นของมันเท่านั้น: การเข้าถึง data ในขณะที่กำลังโหลดเป็นสิ่งที่เป็นไปไม่ได้เลย
type ApiState =
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };
function render(state: ApiState): string {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return state.data.join(", ");
case "error":
return state.message;
}
}ในแต่ละ case TypeScript จะทำให้แคบลง (narrow) ตัว type: หลังจาก case 'error' แล้ว state.message มีอยู่ แต่ state.data ไม่มี กลไกนี้เรียกว่า narrowing เข้ามาแทนที่การตรวจสอบด้วยมือที่เปราะบาง เพิ่มตัวป้องกันความครบถ้วน (exhaustiveness guard) เพื่อล็อกทั้งหมดให้แน่นหนา
function assertNever(value: never): never {
throw new Error("Unhandled case: " + String(value));
}
function label(state: ApiState): string {
switch (state.status) {
case "loading": return "In progress";
case "success": return "Done";
case "error": return "Failed";
default: return assertNever(state);
}
}