Functions and Function Types
Functions are where most bugs hide — wrong arguments, forgotten returns, misused callbacks. Typing them is the single most valuable thing TypeScript does.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Learning objectives#
- Annotate parameters and return types
- Describe a function’s type with (a: A) => R
- Type callback parameters
- Write overloads for functions with several call shapes
Explanation#
Annotate each parameter: function add(a: number, b: number): number. The return type is optional (it is inferred) but useful on exported functions.
A function type expression describes any function with that signature: type Formatter = (value: number) => string.
Use function types for callbacks: function onSave(callback: (id: number) => void). Any matching function can be passed.
A callback typed to return void may still return a value — it is simply ignored. That is why arr.forEach(x => list.push(x)) is allowed.
Overloads list several signatures above one implementation, for functions that accept different argument shapes and return different types.
Syntax#
function greet(name: string): string { … }
const add = (a: number, b: number): number => a + b;
type Handler = (event: MouseEvent) => void;
Code example: Typed functions, callbacks and overloads#
const add = (a: number, b: number): number => a + b;
type Formatter = (value: number) => string;
const rupees: Formatter = v => `₹${v.toFixed(2)}`;
const percent: Formatter = v => `${Math.round(v * 100)}%`;
function formatAll(values: number[], format: Formatter): string[] {
return values.map(format);
}
formatAll([10, 99.5], rupees); // [ '₹10.00', '₹99.50' ]
formatAll([0.25], percent); // [ '25%' ]
formatAll([1], (v: string) => v); // ✗ Type 'number' is not assignable to type 'string'
function retry(task: () => Promise<void>, times: number): Promise<void> {
return task().catch(err => (times > 1 ? retry(task, times - 1) : Promise.reject(err)));
}
// Overloads: one name, two call shapes
function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]): number | number[] {
return Array.isArray(input) ? input.map(Number) : Number(input);
}
const one = parse('42'); // number
const many = parse(['1', '2']); // number[]
formatAll returns [ '₹10.00', '₹99.50' ] and [ '25%' ]. The callback with a string parameter is rejected. parse('42') is typed as number and parse(['1','2']) as number[].This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- add has typed parameters and an explicit return type.
- Formatter is a reusable function type; rupees and percent both match it.
- formatAll accepts any Formatter as a callback.
- A callback with the wrong parameter type is rejected.
- retry takes a function returning a promise — common for network calls.
- The two overload signatures give callers precise return types.
Real-world use case#
Event handlers, array callbacks, middleware (req, res, next) => void and API helpers all rely on function types to prevent misuse.
Common mistakes#
Function accepts any function and returns any. Write the exact signature: (id: number) => void.
Unannotated parameters become any (an error under strict). Always type parameters.
If a union parameter and union return type are clear enough, skip overloads — they are harder to maintain.
Best practices#
- Always type parameters
- Add return types to exported/public functions
- Name reusable signatures with type aliases
- Prefer union parameters or generics over many overloads
Remember this#
(params) => ReturnType — the shape of a function type.
Type the inputs; TS infers the output (but write it on public functions).
Never use Function — say exactly what goes in and out.
Practice exercise#
Your task: Write a type Validator = (value: string) => string | null (null means valid) and a function validateAll(value, validators: Validator[]) that returns the first error or null.
Need a hint?
Show solution
type Validator = (value: string) => string | null;
const required: Validator = v => (v.trim() ? null : 'Required');
const minLen = (n: number): Validator => v => (v.length >= n ? null : `At least ${n} characters`);
function validateAll(value: string, validators: Validator[]): string | null {
for (const check of validators) {
const error = check(value);
if (error) return error;
}
return null;
}
validateAll('ab', [required, minLen(3)]); // 'At least 3 characters'
Mini quiz#
Which describes a function taking a string and returning a boolean?
Want more? Practise all TypeScript MCQs · TypeScript interview questions
My notes#
Saved in this browser.