Functions as values need types too
In Advanced JavaScript you passed functions to map, filter, and event handlers. A function type describes such a value: its parameters and its return type, written with an arrow.
function applyTwice(value: number, fn: (n: number) => number): number { return fn(fn(value)); }
Read (n: number) => number as "a function that takes a number and returns a number". Now the compiler checks both sides of the deal:
- Passing
(n) => n + 1is fine - Passing
(s: string) => sis an error, wrong parameter type - Inside the body, calling
fn(true)is an error too
The callback bugs you debugged by hand in JavaScript become one-line compile errors.
Code exercise · typescript
Run it. Then try applyTwice(5, (s: string) => s) to see the mismatch reported at the call site instead of exploding inside.
Contextual typing: the callback knows its own types
Notice (n) => n + 1 needed no annotation on n. TypeScript already knows the expected callback type from applyTwice, so it types n as number from context. This is contextual typing, and it is why array methods feel so smooth:
const prices: number[] = [3, 10, 6]; const labels = prices.map((p) => "$" + p);
p is automatically number because prices is number[], and labels is inferred as string[] because the callback returns strings. The same map, filter, and reduce you know, now with every step checked.
Code exercise · typescript
Run it and hover nothing: p and sum are typed entirely from context. Then change "$" + p to p.toUpperCase() and run to see the compiler catch it.
Code exercise · typescript
Your turn. Define type WordRule = (word: string) => boolean. Write countMatching(items: string[], rule: WordRule): number that counts items where rule(item) is true. With animals = ["cat", "horse", "dog", "elephant"], print the count of words with length <= 3, then the count of words whose first character (charAt(0)) is "h".