Common mistakes
A misspelt case label
type Text = { type: "text"; body: string };
type Image = { type: "image"; url: string; width: number };
type Attachment = { type: "attachment"; name: string; bytes: number };
type Message = Text | Image | Attachment;
function icon(m: Message): string {
switch (m.type) {
case "text":
return "T";
case "imgae":
return "I";
default:
return "F";
}
}
console.log(icon({ type: "image", url: "/a.png", width: 10 }));
What tsc or Node.js prints
main.ts(10,10): error TS2678: Type '"imgae"' is not comparable to type '"attachment" | "image" | "text"'.
Why, and the fix
A case value must be one of the discriminant's literal types, and tsc lists the ones it accepts. Write case "image". Without tsc, the program would run and quietly print F for every image, because the misspelt case never matches.
Destructuring the discriminant with let
type Text = { type: "text"; body: string };
type Image = { type: "image"; url: string; width: number };
type Attachment = { type: "attachment"; name: string; bytes: number };
type Message = Text | Image | Attachment;
function link(m: Message): string {
let { type } = m;
if (type === "image") {
return m.url;
}
return "";
}
console.log(link({ type: "image", url: "/a.png", width: 10 }));
What tsc or Node.js prints
main.ts(9,14): error TS2339: Property 'url' does not exist on type 'Message'.
Why, and the fix
tsc keeps the link between type and m only for a const (or a parameter that is never reassigned): a let could hold another value by the time of the check. Write const { type } = m;, or check m.type directly.
Destructuring data that only one member has
type Sent = { ok: true; id: number } | { ok: false; error: string };
function report({ ok, id }: Sent): string {
return ok ? "sent #" + id : "failed";
}
console.log(report({ ok: true, id: 7 }));
What tsc or Node.js prints
main.ts(3,23): error TS2339: Property 'id' does not exist on type 'Sent'.
Why, and the fix
A destructuring pattern runs before any check, so it may only take properties that every member has. ok is on both members; id is not. Take the whole object, check ok, then read result.id: function report(result: Sent) { return result.ok ? "sent #" + result.id : "failed"; }.
TypeScript in the browser: the TypeScript 6.0.3 compiler, Apache-2.0, then your browser’s own engine. Licence and source