TypeScript · Functions

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.

Intermediate 5 min Lesson 12 of 29Examples target TypeScript 5.x with "strict": true.
Before you start:Basic Types
0/29 in TypeScript
On this page · 5 min · Intermediate

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#

TypeScript Illustrative
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#

TypeScriptTyped functions, callbacks and overloads Illustrative
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[]
Expected output
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#

  1. add has typed parameters and an explicit return type.
  2. Formatter is a reusable function type; rupees and percent both match it.
  3. formatAll accepts any Formatter as a callback.
  4. A callback with the wrong parameter type is rejected.
  5. retry takes a function returning a promise — common for network calls.
  6. 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#

Using Function as a type

Function accepts any function and returns any. Write the exact signature: (id: number) => void.

Forgetting to annotate parameters

Unannotated parameters become any (an error under strict). Always type parameters.

Overusing overloads

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?
Loop through validators and return the first non-null result.
Show solution
TypeScript Illustrative
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#

Functions and Function Types quizMultiple choice Question 1 of 3

Which describes a function taking a string and returning a boolean?

Score so far: 0/0

Want more? Practise all TypeScript MCQs · TypeScript interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.