TypeScript Function Types Explained
A function type describes what arguments a function accepts and what it returns. Learn the arrow syntax for function types, how to use type aliases, and where function types appear in real code.
A function type is a type that describes a function's signature: what arguments it accepts and what it returns. In TypeScript, you write function types with arrow syntax, similar to an arrow function but without a body. The type exists only at compile time and does not change the JavaScript output.
Here is a function type that describes a function taking a string and returning a number:
type StringToNumber = (input: string) => number;The StringToNumber alias now represents any function that matches that signature. You can use it to type a variable, a parameter, or a return value.
The Arrow Syntax for Function Types
The syntax looks like an arrow function, but it describes a type, not a value. The parts are the parameter list in parentheses, the => arrow, and the return type:
(param1: Type1, param2: Type2) => ReturnTypeEach parameter gets a name and a type just like a normal function signature, and the part after the arrow is the return type. Here is a concrete example that follows this pattern. The variable below is typed as a function that takes a string and returns a string:
let greet: (name: string) => string;
greet = (name) => {
return `Hello, ${name}!`;
};
console.log(greet("Alice"));
// Output: Hello, Alice!TypeScript checks that any function assigned to this variable matches the type. Reassigning it with a function that takes a number instead of a string breaks that contract, so the compiler rejects the assignment with this exact error:
let greet: (name: string) => string;
greet = (x: number) => x.toString();The parameter type does not match the declared signature, so TypeScript reports this exact error instead of allowing the assignment to happen silently:
Type '(x: number) => string' is not assignable to type '(name: string) => string'.
Types of parameters 'x' and 'name' are incompatible.
Type 'string' is not assignable to type 'number'.The compiler caught the mismatch before the code ever ran. The function type told TypeScript exactly what to expect, and the assigned function broke that contract.
Where Function Types Appear
Function types show up in three common places: callback parameters, variables that hold functions, and return types that produce functions.
Callback Parameters
The most common place you see a function type is as a callback parameter. The built-in array method forEach takes a callback typed as a function type. For a closer look at writing callback types yourself, see type callback functions in TypeScript.
const names = ["Alice", "Bob", "Charlie"];
names.forEach((name: string, index: number) => {
console.log(`${index}: ${name}`);
});TypeScript infers a matching function type for the callback from the array itself, so you rarely write that type by hand. The inferred type still checks that your callback uses the parameters correctly.
When you write your own function that accepts a callback, you provide the function type explicitly:
function fetchData(callback: (data: string) => void) {
const result = "some data";
callback(result);
}
fetchData((data) => {
console.log(data.toUpperCase());
});
// Output: SOME DATAThe parameter is typed as a function that takes a string and returns nothing. TypeScript now checks every call to this function and ensures the argument matches the signature.
Variables Holding Functions
A variable can also hold a reference to a function. Declare it with a function type, and TypeScript checks every value assigned to it later:
let transform: (value: number) => number;
transform = (n) => n * 2;
console.log(transform(5));
// Output: 10This is useful when the function is assigned later, for example from a configuration object or a conditional branch. The type ensures every assignment path produces a compatible function.
Functions Returning Functions
A function can also return another function. The return type annotation itself uses a function type, telling callers exactly what kind of function they get back:
function createMultiplier(factor: number): (value: number) => number {
return (value) => value * factor;
}
const triple = createMultiplier(3);
console.log(triple(10));
// Output: 30The return type tells TypeScript and the reader that this function returns another function. The caller gets full type checking on the returned function.
Naming Function Types With Type Aliases
Writing the full arrow type inline works, but it becomes hard to read when the type appears in multiple places or when the parameter list is long. Use a type alias to give the function type a name:
type StringPredicate = (value: string) => boolean;
function filterStrings(items: string[], predicate: StringPredicate): string[] {
return items.filter(predicate);
}This function accepts the alias as its predicate type instead of repeating the full arrow syntax. Calling it with a short predicate keeps the call site easy to read:
const longNames = filterStrings(["Al", "Alice", "Bob"], (name) => name.length > 2);
console.log(longNames);
// Output: ["Alice"]The alias makes the intent clear: a predicate is a function that returns a boolean. If the predicate shape changes later, you update one alias instead of every inline type. This matters most in shared code, such as a utilities module, where several functions accept the same kind of callback and should describe it the same way.
Void Return Type
When a function does not return a meaningful value, give it a void return type. This tells callers that any returned value should be ignored:
type Logger = (message: string) => void;
const logToConsole: Logger = (msg) => {
console.log(`[LOG] ${msg}`);
};
logToConsole("User signed in");
// Output: [LOG] User signed inA function typed with a void return can still return a value at runtime, but TypeScript tells callers not to use it. This matches how forEach works: the callback can return anything, but forEach ignores it. The void return type never appears in the compiled JavaScript because it is a compile-time-only signal, so it has no effect on how the function actually behaves once it runs.
Function Parameter Count Compatibility
TypeScript allows a function with fewer parameters to be assigned where a function type expects more. This matches JavaScript behavior: extra arguments are simply ignored at runtime.
type Handler = (event: string, timestamp: number) => void;
// Fewer parameters is fine
const simpleHandler: Handler = (event) => {
console.log(event);
};
simpleHandler("click", Date.now());
// Output: clickThis function ignores the second parameter, but TypeScript accepts it because the caller still provides both arguments. The reverse is not true: a function that expects two parameters cannot be assigned where the type expects one, because the function would miss an argument it needs.
This rule makes callbacks much more ergonomic. You can write a forEach callback that takes only the item, without listing the index and array parameters you do not need.
Common Mistakes
Using non-arrow syntax for a function type. Function types always use =>, never a colon after the parameter list. Writing the colon form is not just bad style, it fails to compile:
// Wrong: this is a syntax error, not a valid type
type Bad = (x: number): number;
// Correct: arrow syntax
type Good = (x: number) => number;The colon-after-parentheses syntax only exists for call signatures inside object types, such as { (x: number): number }. As a standalone type alias it is invalid syntax, so the compiler reports the missing arrow immediately:
'=>' expected.Forgetting that the parameter name is required. Even though TypeScript only checks the types, the parameter name must be present in the syntax:
// Wrong: missing parameter name
type Bad = (string) => number;
// TypeScript interprets this as "a parameter named string of type any"
// Correct: always include the name
type Good = (value: string) => number;Confusing a function type with a function call. A function type describes a signature. It does not call the function:
type Validator = (value: string) => boolean;
// This is a type, not a call. Do not try to invoke Validator directly.
// Instead, declare a variable of type Validator and assign a function to it.For the next step, see type function parameters in TypeScript to learn how to annotate each parameter individually.
Rune AI
Key Insights
- A function type uses arrow syntax: (param: Type) => ReturnType.
- Function types describe the call signature, not the implementation.
- Use type aliases to give function types a reusable name.
- A function with fewer parameters is compatible with a function type expecting more.
- Function types only exist at compile time and are erased from the JavaScript output.
Frequently Asked Questions
What is a function type in TypeScript?
Can I name a function type?
Does the parameter name matter in a function type?
Conclusion
A function type is a type-level description of a function's signature. You write it with arrow syntax, can store it in a type alias, and use it to type callbacks, variables, and function parameters. The syntax is (params) => ReturnType. The type only exists at compile time and has zero impact on the JavaScript that runs.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.