JSDoc tag

@template

  • Checked by TypeScript
  • Tested with TypeScript 5.9

@template T declares a type parameter named T for the function, class, @typedef or @callback it belongs to. Inside the same comment, and in the body, T can be used like any type. It is the JavaScript spelling of <T> in TypeScript.

Callers never write the type argument; JavaScript has no syntax for it. TypeScript infers T from the arguments at each call, so first(["S", "M"]) returns string | undefined and first([19.5]) returns number | undefined.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
A type parameter /** * @template T * @param {T[]} items * @returns {T | undefined} */ function first<T>(items: T[]): T | undefined {}
With a constraint /** @template {{ id: string }} T */ <T extends { id: string }>
With a default /** @template [T=unknown] */ <T = unknown>
Several parameters /** @template K, V */ <K, V>

Examples

list.js list.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @template T
 * @param {T[]} items
 * @returns {T | undefined}
 */
export function first(items) {
  return items[0];
}

const size = first(["S", "M", "L"]);
const price = first([19.5, 12]);
size?.toLowerCase();
price?.toFixed(2);
export function first<T>(items: T[]): T | undefined {
  return items[0];
}

const size = first(["S", "M", "L"]);
const price = first([19.5, 12]);
size?.toLowerCase();
price?.toFixed(2);
A generic function with @template.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
list.js list.ts Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: list.js(12,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. list.ts(7,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. list.js(12,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. list.ts(7,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. list.js(12,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. list.ts(7,9): error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'. checked 21 October 2026
/**
 * @template {{ id: string }} T
 * @param {T[]} items
 * @returns {Map<string, T>}
 */
export function byId(items) {
  return new Map(items.map((item) => [item.id, item]));
}

byId([{ id: "TEE-01", price: 19.5 }]);
byId([{ sku: "TEE-01" }]);error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'.
export function byId<T extends { id: string }>(items: T[]): Map<string, T> {
  return new Map(items.map((item) => [item.id, item]));
}

byId([{ id: "TEE-01", price: 19.5 }]);
byId([{ sku: "TEE-01" }]);error TS2353: Object literal may only specify known properties, and 'sku' does not exist in type '{ id: string; }'.
Constraining a type parameter.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
result.js result.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @template [T=unknown]
 * @typedef {{ ok: true, data: T } | { ok: false, error: string }} Result
 */

/** @type {Result<number>} */
const count = { ok: true, data: 3 };

/** @type {Result} */
const anything = { ok: true, data: "whatever" };

/** @param {Result<number>} result */
export function show(result) {
  return result.ok ? result.data.toFixed(0) : result.error;
}

show(count);
export { anything };
type Result<T = unknown> = { ok: true; data: T } | { ok: false; error: string };

const count: Result<number> = { ok: true, data: 3 };

const anything: Result = { ok: true, data: "whatever" };

export function show(result: Result<number>) {
  return result.ok ? result.data.toFixed(0) : result.error;
}

show(count);
export { anything };
A default type argument on a generic @typedef.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Constraints

A type in braces before the name constrains the parameter: @template {{ id: string }} T accepts any type with a string id. Arguments that do not fit are errors, and inside the function you can use item.id safely.

A constraint applies only to the first name in a list. In @template {string} K, V, K must be a string and V is unconstrained; give each constrained parameter its own @template line.

Defaults

Brackets with an equals sign give a default: @template [T=unknown]. TypeScript 4.5 added defaults in JSDoc. They matter on a generic @typedef or class, where Result written without arguments then means Result<unknown>, as in the third example. A constraint and a default can be combined: @template {string | number} [T=number].

Classes and typedefs

On a class, @template T above the class makes T available to every member's JSDoc, and new Box("x") infers it from the constructor's parameters. On a @typedef or @callback, put @template first in the same comment.

Gotchas

  • A type parameter that appears only in the return type cannot be inferred and falls back to its constraint or unknown. Make it appear in a parameter, or type the result at the call site.
  • Writing first<string>(items) in a .js file does not pass a type argument: JavaScript reads it as two comparisons, and tsc reports errors about the < and > operators.
  • Generic type parameter declarations, function first<T>(), are TypeScript syntax and an error in a .js file (TS8004).

Questions

How do I write generics in JSDoc?

Declare the type parameter with @template T in the function's comment and use T in its @param and @returns types. TypeScript infers it at each call.

Sources

Last reviewed 20 October 2026.