Narrowing in TypeScript
The compiler follows your checks: typeof, in, instanceof, truthiness.
type Success = { ok: true; value: string };
type Failure = { ok: false; error: Error };
type Outcome = Success | Failure;
function describe(outcome: Outcome): string {
if (outcome.ok) return outcome.value.toUpperCase();
return outcome.error.message;
}
function describeUnion(input: string | number | Date | null): string {
if (input === null) return "nothing";
if (typeof input === "string") return input.trim();
if (typeof input === "number") return input.toFixed(1);
return input.toISOString();
}
function hasSteps(value: { steps?: number[] } | { slug: string }): boolean {
return "steps" in value && (value.steps?.length ?? 0) > 0;
}
console.log(describe({ ok: true, value: "done" }));
console.log(describeUnion(new Date(0)), hasSteps({ steps: [1] }));
How it works
innarrows a union by the presence of a property.instanceofnarrows classes;typeofnarrows primitives.- A discriminant property is the most readable narrowing of all.
Keywords and builtins used here
DateErrorOutcomebooleanfalsefunctionifnumberreturnstringtruetype
The run, in numbers
- Lines
- 22
- Characters to type
- 759
- Tokens
- 212
- Three-star pace
- 95 tpm
At the three-star pace of 95 tokens a minute, this run takes about 134 seconds.
Step 2 of 4 in Narrowing, step 8 of 23 in Types & annotations.