Type predicates in TypeScript
A function returning x is T teaches the compiler what you checked.
type Run = { lang: string; tpm: number };
function isRun(value: unknown): value is Run {
return (
typeof value === "object" &&
value !== null &&
"lang" in value &&
typeof (value as Run).lang === "string" &&
typeof (value as Run).tpm === "number"
);
}
function assertRun(value: unknown): asserts value is Run {
if (!isRun(value)) throw new TypeError("not a run");
}
function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
const raw: unknown = { lang: "ts", tpm: 98 };
if (isRun(raw)) console.log(raw.lang.toUpperCase());
assertRun(raw);
console.log(raw.tpm + 1);
console.log([1, null, 2, undefined].filter(isDefined));
How it works
- The predicate narrows at every call site.
- It is the honest way to validate data from outside.
- An assertion signature narrows without returning a value.
Keywords and builtins used here
Tasconstfunctionifnumberreturnstringthrowtypeunknown
The run, in numbers
- Lines
- 26
- Characters to type
- 679
- Tokens
- 193
- Three-star pace
- 95 tpm
At the three-star pace of 95 tokens a minute, this run takes about 122 seconds.
Step 3 of 4 in Narrowing, step 9 of 23 in Types & annotations.