Skip to content
Function Types
step 1/5

Reading — step 1 of 5

Learn

~3 min readFunctions

Functions in TypeScript get parameter types and a return type. Annotating them is one of the highest-value things you can do — most bugs are wrong types flowing through function boundaries.

Annotating function declarations

function add(a: number, b: number): number {
    return a + b;
}

const multiply = (a: number, b: number): number => a * b;

The return type can be inferred from the body. Annotating it explicitly is still recommended for public APIs — catches mistakes inside the body and documents intent.

Optional parameters

function greet(name: string, greeting?: string): string {
    return `${greeting ?? "Hello"}, ${name}!`;
}

greet("Alice");                  // OK — greeting omitted
greet("Bob", "Howdy");           // OK

? makes the parameter optional. Inside the function, the type is string | undefined. Optional parameters MUST come after required ones.

Default values

function greet(name: string, greeting: string = "Hello"): string {
    return `${greeting}, ${name}!`;
}

With a default, the parameter is implicitly optional, and inside the function it's just string (not string | undefined).

Rest parameters

function sum(...nums: number[]): number {
    return nums.reduce((a, b) => a + b, 0);
}

sum(1, 2, 3);     // 6

Rest parameters are typed as an array. The caller spreads however many arguments they want.

Function-type aliases

type Predicate = (n: number) => boolean;

const isPositive: Predicate = n => n > 0;
const isEven: Predicate = n => n % 2 === 0;

Giving a callable shape a name makes APIs cleaner. Anywhere you need a number-to-boolean callback, declare it as Predicate.

Using function types in interfaces

interface EventHandler {
    onClick(e: MouseEvent): void;
    onSubmit: (data: FormData) => boolean;
}

Both method-shorthand and function-property syntax work for declaring callable members.

Returning void vs undefined

function logIt(msg: string): void {
    console.log(msg);
    // returning is optional
}

void says "the caller shouldn't depend on a return value." The function CAN return undefined, but void-typed functions in callback positions are special — they let you pass functions that return non-void without TypeScript complaining.

never for impossible returns

function throwError(msg: string): never {
    throw new Error(msg);
}

function loopForever(): never {
    while (true) {}
}

never is the bottom type — it represents "this function never returns normally." Useful for exhaustiveness checks in switch statements.

Function overloads (briefly)

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);
}

parse("42");           // typed as number
parse(["1", "2"]);     // typed as number[]

Multiple signatures + one implementation. The signatures are what callers see; the implementation is hidden. Useful when one function does meaningfully different things based on argument types.

Common mistakes

  • Forgetting return type on async functions — should be Promise<T>, not T.
  • Required after optional: function f(a?: string, b: number) is a compile error (TS1016: a required parameter cannot follow an optional one). Optionals come last.
  • Using any for parameter types — type the actual shape. If genuinely flexible, use a union or generic.
  • Wrong function-type variance — methods (onClick(e): void) and function properties (onClick: (e) => void) behave differently in strict mode.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…