Question
I have this TypeScript interface:
interface Param {
title: string;
callback: any;
}
I want callback to be typed as a function, without using the universal any type. I tried something like this:
interface Param {
title: string;
callback: function;
}
but TypeScript does not accept it. How should I properly define the type for a callback function used as a property in an interface?
Short Answer
By the end of this page, you will understand how to type callback functions in TypeScript interfaces using function signatures, when to use Function, why it is usually too broad, and how to define safer callback types with parameters and return values.
Concept
In TypeScript, functions have their own types. You do not usually write function as a type name. Instead, you describe a function by its parameter list and return type.
For example:
(type for a function) => returnType
A callback is just a function passed to another part of your program so it can be called later. Because TypeScript checks types, it wants to know:
- What arguments the callback receives
- What the callback returns
That is why this is valid:
interface Param {
title: string;
callback: () => void;
}
This means:
callbackis a function- it takes no arguments
- it returns nothing (
void)
If you truly want “any function” without describing its exact shape, TypeScript has a built-in Function type:
interface Param {
title: string;
callback: Function;
}
However, Function is usually not the best choice because it is too broad. It tells TypeScript almost nothing useful about how the function should be called.
In real code, a specific callback signature is much better because it gives:
- autocomplete
- safer calls
- clearer intent
- better error checking
So the best practice is usually to define the callback with a proper function signature instead of using any, function, or even Function.
Mental Model
Think of a callback type like a job description.
anymeans: “This worker can be anything.”Functionmeans: “This worker is at least a person, but I do not know their skills.”() => voidmeans: “This worker takes no input and performs a task.”(name: string) => numbermeans: “This worker receives a string and gives back a number.”
The more precise the job description, the easier it is to use the worker correctly.
If you only say “function,” that is too vague for TypeScript. It wants the shape of the function, not just the general idea that it is callable.
Syntax and Examples
Basic function type syntax
A function type is written like this:
(param1: Type1, param2: Type2) => ReturnType
Example: callback with no arguments
interface Param {
title: string;
callback: () => void;
}
const item: Param = {
title: "Save",
callback: () => {
console.log("Saved");
}
};
Here:
callbacktakes no argumentscallbackreturnsvoid
Example: callback with arguments
interface Param {
title: string;
callback: (message: string) => void;
}
const item: Param = {
title: "Notify",
callback: (message) => {
console.log(message);
}
};
Now the callback must accept a string.
Example: callback with a return value
interface Param {
title: string;
callback: (value: number) => boolean;
}
const item: Param = {
title: "Check",
callback: (value) => {
return value > 10;
}
};
This callback takes a number and returns a boolean.
If you want any function at all
interface Param {
title: string;
callback: Function;
}
This works, but it is less safe than a specific signature.
Using a named type alias
For readability, you can extract the callback type:
type Callback = (message: string) => void;
interface Param {
title: string;
callback: Callback;
}
This is common in larger codebases because it makes the interface easier to read and reuse.
Step by Step Execution
Consider this example:
interface Param {
title: string;
callback: (count: number) => string;
}
const param: Param = {
title: "Counter",
callback: (count) => {
return `Count is ${count}`;
}
};
const result = param.callback(3);
console.log(result);
Step by step:
-
TypeScript reads the interface.
titlemust be a string.callbackmust be a function that takes anumberand returns astring.
-
The
paramobject is checked against the interface.title: "Counter"is valid because it is a string.callback: (count) => { ... }is checked.
-
TypeScript verifies the callback.
- It sees one parameter:
count - It expects
countto be anumber - It expects the function to return a
string
- It sees one parameter:
-
param.callback(3)is valid.3is a number- the callback returns
Count is 3
-
resultbecomes a string.
If you tried this instead:
param.callback("hello");
TypeScript would report an error because the callback expects a number, not a string.
Real World Use Cases
Callback types appear everywhere in TypeScript applications.
Event handlers
interface ButtonConfig {
label: string;
onClick: () => void;
}
Used in UI code when a button should run some logic.
Data processing
interface Processor {
transform: (input: string) => string;
}
Used when formatting text, cleaning data, or converting values.
API response handling
interface RequestOptions {
onSuccess: (data: string) => void;
onError: (message: string) => void;
}
Used when different functions handle successful and failed requests.
Array utilities
Methods like map, filter, and forEach all use callbacks:
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2);
TypeScript uses callback types to ensure map is called correctly.
Real Codebase Usage
In real projects, developers rarely leave callback types vague unless they truly have no constraints.
Common pattern: define exact signatures
interface Task {
run: () => Promise<void>;
}
This makes usage predictable.
Common pattern: reusable type aliases
type ErrorHandler = (error: Error) => void;
type SuccessHandler = (message: string) => void;
interface Handlers {
onSuccess: SuccessHandler;
onError: ErrorHandler;
}
This avoids repeating long function signatures.
Common pattern: optional callbacks
interface Config {
title: string;
onComplete?: () => void;
}
The ? means the callback may or may not be provided.
Common pattern: validation callbacks
interface FieldRule {
validate: (value: string) => boolean;
}
This is common in forms and input checking.
Common pattern: async callbacks
interface Job {
execute: () => Promise<string>;
}
Used when the callback performs asynchronous work.
Guarding optional callbacks before calling
function finish(config: Config) {
if (config.onComplete) {
config.onComplete();
}
}
This is safer than assuming the function always exists.
Common Mistakes
1. Using function as a type
This is invalid TypeScript:
interface Param {
callback: function;
}
Why it fails:
functionis not a valid type keyword in TypeScript type annotations.- You must use a function signature like
() => voidor the broadFunctiontype.
2. Using any for callbacks
interface Param {
callback: any;
}
Why it is risky:
- TypeScript cannot protect you
- You can call the callback incorrectly
- Errors move from compile time to runtime
3. Using Function when a specific signature is better
interface Param {
callback: Function;
}
This is allowed, but weak.
Problem:
const p: Param = {
callback: (x: number) => x * 2
};
Later, someone might try:
p.callback("wrong input");
TypeScript gives much less help because Function is too general.
4. Forgetting the return type
Broken example:
interface Param {
callback: (name: string);
}
Correct version:
interface Param {
callback: (name: string) => void;
}
A function type needs both:
- parameter list
- return type
5. Mismatching the callback implementation
interface Param {
callback: (value: number) => string;
}
const p: Param = {
callback: (value) => value * 2
};
Problem:
value * 2returns a number- the interface expects a string
Correct version:
const p: Param = {
callback: (value) => String(value * 2)
};
Comparisons
| Approach | Example | Valid? | Type Safety | Best Use |
|---|---|---|---|---|
any | callback: any | Yes | Very low | Avoid when possible |
function | callback: function | No | None | Invalid in TypeScript |
Function | callback: Function | Yes | Low | Only when any callable value is acceptable |
| Specific function type | callback: () => void | Yes | High | Best for most cases |
| Named type alias | callback: Callback | Yes | High | Best when reused |
Function vs specific signature
callback: Function
- accepts any function
- gives poor information about parameters and return value
callback: (id: number) => string
- clearly describes the callback
- safer to call
- easier to maintain
Inline type vs type alias
Inline:
interface Param {
callback: (value: string) => boolean;
}
Type alias:
type Callback = (value: string) => boolean;
interface Param {
callback: Callback;
}
Use inline types for simple one-off cases. Use type aliases when the same callback shape appears in multiple places.
Cheat Sheet
// Best practice: define the exact callback signature
interface Param {
title: string;
callback: () => void;
}
// Callback with parameters
interface Param {
title: string;
callback: (message: string) => void;
}
// Callback with return value
interface Param {
title: string;
callback: (value: number) => boolean;
}
// Broad function type (allowed, but not ideal)
interface Param {
title: string;
callback: Function;
}
Rules
- Do not use
functionas a type - Prefer a specific function signature over
any - Prefer a specific function signature over
Function - A function type uses this form:
(params) => returnType
- Use
voidwhen nothing is returned - Use
?for optional callbacks
Common patterns
onClick: () => void
onChange: (value: string) => void
validate: (input: string) => boolean
load: () => Promise<Data>
Reusable alias
type Callback = (value: string) => void;
Edge case
If you do not know the exact signature yet, Function is possible, but it removes much of TypeScript's safety.
FAQ
Why is function not accepted as a type in TypeScript?
Because function is not a valid type annotation keyword. TypeScript expects either a function signature like () => void or a built-in type such as Function.
Should I use Function for callbacks in TypeScript?
Only if you truly want any callable function and do not care about parameters or return type. In most cases, a specific function signature is better.
What is the correct way to type a callback with no arguments?
Use:
() => void
This means the function takes no arguments and returns nothing.
How do I type a callback that returns a value?
Use a return type after the arrow:
(value: number) => string
Can I make a callback optional in an interface?
Yes:
interface Param {
callback?: () => void;
}
Is any the same as Function?
No. any disables type checking almost completely. Function at least says the value should be callable, but it is still very broad.
When should I use a type alias for a callback?
Use a type alias when the same callback type is reused or when the inline signature is getting too long.
Mini Project
Description
Build a small TypeScript configuration object for a notifier system. Each notifier has a title and a callback function that runs when a message is sent. This demonstrates how to define and use callback types safely in an interface.
Goal
Create a typed interface with a callback property and use it to run functions with the correct parameter and return types.
Requirements
- Create an interface with a
titleproperty and a typedcallbackproperty. - The callback must accept a string message.
- The callback must return a string.
- Create at least two objects that follow the interface.
- Call each callback and log the result.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.