@callback declares a named function type. The lines after it are ordinary @param and @returns tags, and together they describe the function's signature. TypeScript reads the block as type Rule = (value: string) => string | null, and the name works anywhere a type does.
Use it for the shape of a function that other code passes around: validators, event listeners, comparison functions, middleware. A @typedef with an arrow type does the same job on one line; @callback reads better when each parameter needs a description.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| A named function type | /**
* @callback Rule
* @param {string} value
* @returns {string | null}
*/ | type Rule = (value: string) => string | null; |
| Using it | /** @type {Rule} */
const required = (value) => …; | const required: Rule = (value) => …; |
| A generic callback | /**
* @template T
* @callback Listener
* @param {T} payload
*/ | type Listener<T> = (payload: T) => void; |
Examples
/**
* @callback Rule
* @param {string} value
* @returns {string | null} an error message, or null when the value is fine
*/
/** @type {Rule} */
const required = (value) => (value.trim() ? null : "Required");
/** @type {Rule} */
const shortEnough = (value) => (value.length <= 40 ? null : "40 characters at most");
/**
* @param {string} value
* @param {Rule[]} rules
* @returns {string[]}
*/
export function validate(value, rules) {
return rules.map((rule) => rule(value)).filter((message) => message !== null);
}
validate("Cotton tee", [required, shortEnough]);type Rule = (value: string) => string | null;
const required: Rule = (value) => (value.trim() ? null : "Required");
const shortEnough: Rule = (value) => (value.length <= 40 ? null : "40 characters at most");
export function validate(value: string, rules: Rule[]): string[] {
return rules.map((rule) => rule(value)).filter((message) => message !== null);
}
validate("Cotton tee", [required, shortEnough]);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @callback Rule
* @param {string} value
* @returns {string | null}
*/
/** @type {Rule} */
const maxLength = (value) => value.length;error TS2322: Type 'number' is not assignable to type 'string'.
export { maxLength };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @template T
* @callback Listener
* @param {T} payload
* @returns {void}
*/
/**
* @template T
* @param {Listener<T>[]} listeners
* @param {T} payload
*/
export function emit(listeners, payload) {
for (const listener of listeners) listener(payload);
}
/** @type {Listener<{ sku: string, quantity: number }>} */
const logAdd = (item) => console.log(`${item.quantity} × ${item.sku}`);
emit([logAdd], { sku: "TEE-01", quantity: 2 });
emit([logAdd], { sku: "TEE-01", quantity: "2" });error TS2322: Type 'string' is not assignable to type 'number'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Where the tag goes
A @callback block stands on its own in a /** */ comment; it does not need to sit above any code. Its name is visible in the whole file and, in a module, can be imported by other files with @import or import("./file.js").Rule.
Apply it with @type {Rule} on a variable, or use Rule inside other types: @param {Rule[]} rules. A function typed this way gets its parameter types from the callback, so (value) => … needs no @param of its own.
Generic callbacks
Put @template T in the same comment, before @callback, to make the callback generic. Listener<{ sku: string, quantity: number }> then fixes the payload type, and a call with the wrong payload is an error, as the third example shows.
@callback or @typedef?
/** @typedef {(value: string) => string | null} Rule */ declares the same type. Choose @callback when the parameters deserve a sentence each, since each @param line can carry a description that editors show while you type the arguments.
Gotchas
- A
@callbackdescribes one call signature. For a function with properties as well (a function object with.displayName, say), use a@typedefwith an object type that has a call signature:{{ (value: string): string, displayName: string }}. @returnsis optional in a callback. Without it, the return type isany, which accepts anything a function returns and lets callers use the result as anything; write@returns {void}when the result is ignored.
Questions
How do I type a function parameter in JSDoc?
Either inline, @param {(value: string) => boolean} test, or with a named type from @callback or @typedef. The named type is easier to reuse and to read in error messages.
Sources
- JSDoc Reference: @callback · TypeScript handbook
- @callback · JSDoc
- More on Functions: function type expressions · TypeScript handbook
Last reviewed 20 October 2026.