A function type describes the parameters and the return value of a function, written with an arrow: (a: number, b: number) => number. Give it a name with type and you can use it for variables, parameters and object properties.
The function assigned to add needs no annotations: its parameter types come from Operation. This is called contextual typing, and it is the main reason to name function types.
Function Type Syntax
The shape is (parameters) => ReturnType. Each parameter needs a name and a type. The names are there for readability and editor hints; any function with compatible parameter types matches, whatever it calls them.
type Predicate = (value: number) => boolean;
type Formatter = (value: number, digits?: number) => string; // optional parameter
type Logger = (...parts: string[]) => void; // rest parameter
type Factory = () => { id: number }; // no parameters
The name is not optional. (string) => void declares a parameter called string with no type, and strict mode rejects it with TS7051: Parameter has a name but no type. Did you mean 'arg0: string'?. Write (value: string) => void.
Typing Arrow Functions
An arrow function can be typed two ways. Annotate the function itself, or annotate the variable with a function type and let the parameters be inferred.
Form 1 is the usual choice for a standalone function. Form 3 pays off when several functions share one signature (handlers, comparators, converters), because the signature is written once and a change to it is checked everywhere.
Callback Types
A parameter whose type is a function type is a callback. The caller's function is checked against it, and its parameters are inferred from it.
Two rules make callbacks pleasant to use:
- Fewer parameters is fine. A function that takes one parameter can be passed where two are offered. JavaScript ignores extra arguments, so TypeScript allows it. More parameters than the type offers is an error (
Target signature provides too few arguments.). - A
voidreturn accepts anything. A callback typed(...) => voidmay return a value; the caller promises not to use it. That is whylist.forEach((x) => other.push(x))compiles even thoughpushreturns a number.
The parameter types must still be compatible. Passing (x: string) => ... where (a: number, b: number) => number is expected fails with Types of parameters 'x' and 'a' are incompatible.
Call Signatures
(n: number) => string is shorthand for an object type with a call signature: { (n: number): string }. You need the long form when the function also carries properties.
TypeScript lets you add properties to a function declared with const in the same scope, and it tracks them in the function's type. An interface can hold a call signature too: interface Counter { (): number; count: number }.
A construct signature describes something called with new. It adds new in front: new (name: string) => User, or { new (name: string): User } in object form. It is how you type a parameter that receives a class.
Method Syntax vs Property Syntax
In an object type, a function member can be written as a method, handle(value: string): void, or as a property holding a function, handle: (value: string) => void. They look interchangeable but are checked differently under strict:
The compiler reports:
index.ts(8,27): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string | number) => void'.
Types of parameters 'value' and 'value' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
The error is right: onlyStrings cannot handle a number. The method form lets the same mistake through (method parameters are checked "bivariantly" for historical reasons), and a.handle(42) would crash at run time with TypeError: value.toUpperCase is not a function. Delete the b line to see that crash. When you write your own object types, the property form catches more.
Avoid the Function Type
Function is the built-in type every function value satisfies. It is almost never what you want: TypeScript does not know the parameters or the return type, so every call is accepted and returns any.
Replace Function with the real signature. When you truly accept any function (a generic debounce, a logging wrapper), (...args: never[]) => unknown accepts every function and still keeps the result unknown instead of any. For functions whose types depend on their input, see generics: a generic function type looks like <T>(value: T) => T.
Frequently Asked Questions
How do you define a function type in TypeScript?
Use the arrow syntax: (a: number, b: number) => number. Give it a name with a type alias, type Compare = (a: number, b: number) => number;, and use that name for variables, parameters and properties. The parameter names are part of the syntax but only for documentation: a function with different parameter names still matches.
How do I type a callback parameter in TypeScript?
Write the function type as the parameter's type: function onEach(items: string[], cb: (item: string, index: number) => void) { ... }. Callers can pass a function that takes fewer parameters, and the callback's own parameters are inferred from that type, so onEach(list, (item) => ...) needs no annotation.
Why should I not use the Function type in TypeScript?
Function accepts any function and calling it is not checked: any arguments are allowed and the result is any. Write the real signature instead, such as () => void or (value: string) => number, or (...args: never[]) => unknown when you truly accept every function.
What is the difference between a function type and a call signature?
They describe the same thing. (n: number) => string is shorthand for the object type { (n: number): string }. The call signature form is needed when the function also has properties, for example { (n: number): string; label: string }.
How do I type an arrow function in TypeScript?
Either annotate its parameters and return type inline, const half = (n: number): number => n / 2;, or give the variable a function type and let the parameters be inferred: const half: (n: number) => number = (n) => n / 2;.