Lessons · TypeScript · the type names the edge
The type names the edge; the test proves it
A return type of number | undefined or number | null admits the empty case out loud, forces every caller to handle it, and gives the test a case to prove.
Hone is a place to practise programming. This is one of its lessons, written out in full and free to read without an account.
What it is for
xs.reduce((a, b) => a + b) compiles on number[] and throws on []; the types are satisfied and the value is not. That gap is exactly what tests at the edges fill.
How to think about it
Ask what the smallest input is and put its answer in the type: undefined, null, or a chosen number. Then test nothing, one, and everything the same.
Worked example
function check(ok: boolean, msg: string): void { if (!ok) throw new Error(msg); }function head(xs: number[]): number | undefined { return xs[0]; }The type admits the empty case.check(head([]) === undefined, 'nothing gives undefined');Nothing.
check(head([7]) === 7, 'one gives it');One.
const n = head([5, 5, 5]);Everything the same.
console.log(n === undefined ? 'empty' : n * 2);10: the caller handled the case the type forced.
Your turn
Admit the empty case in the type.
function last(xs: number[]): number | { return xs[xs.length - 1]; }Solve one with the compiler running
The trap
const n: number = head([]). The compiler refuses it, because the type said undefined can happen, and the test is what shows you when.