Type expression

Tuples

  • Collections
  • Tested with TypeScript 5.9

A tuple type such as {[number, number]} describes an array with exactly two elements, both numbers. Each position can have its own type, {[string, number]}, and TypeScript checks the length as well as the elements.

Tuples suit small fixed groups returned from a function, such as a minimum and maximum, or a key and a value. Elements can be named ([min: number, max: number]), optional (quantity?: number) and followed by a rest element (...values: number[]).

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Fixed length /** @type {[number, number]} */ : [number, number]
Named elements /** @returns {[min: number, max: number]} */ (): [min: number, max: number]
Optional element /** @type {[sku: string, quantity?: number]} */ : [sku: string, quantity?: number]
Rest elements /** @type {[label: string, ...values: number[]]} */ : [label: string, ...values: number[]]

Examples

range.js range.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
/**
 * @param {number[]} prices
 * @returns {[min: number, max: number]}
 */
export function priceRange(prices) {
  return [Math.min(...prices), Math.max(...prices)];
}

const [low, high] = priceRange([19.5, 12, 30]);

/** @type {[sku: string, quantity?: number]} */
const line = ["TEE-01"];

/** @type {[label: string, ...values: number[]]} */
const row = ["Sales", 120, 98, 143];

export { low, high, line, row };
export function priceRange(prices: number[]): [min: number, max: number] {
  return [Math.min(...prices), Math.max(...prices)];
}

const [low, high] = priceRange([19.5, 12, 30]);

const line: [sku: string, quantity?: number] = ["TEE-01"];

const row: [label: string, ...values: number[]] = ["Sales", 120, 98, 143];

export { low, high, line, row };
Tuples: fixed length, named, optional and rest elements.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
point.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: point.js(3,7): error TS2322: Type '[number, number, number]' is not assignable to type '[x: number, y: number]'. Source has 3 element(s) but target allows only 2. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. point.js(3,7): error TS2322: Type '[number, number, number]' is not assignable to type '[x: number, y: number]'. Source has 3 element(s) but target allows only 2. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. point.js(3,7): error TS2322: Type '[number, number, number]' is not assignable to type '[x: number, y: number]'. Source has 3 element(s) but target allows only 2. checked 21 October 2026
/** @type {[x: number, y: number]} */
const point = [10, 20, 30];error TS2322: Type '[number, number, number]' is not assignable to type '[x: number, y: number]'.
  Source has 3 element(s) but target allows only 2.

export { point };
A tuple checks its length.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
range.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: range.js(8,7): error TS2322: Type 'number[]' is not assignable to type '[number, number]'. Target requires 2 element(s) but source may have fewer. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. range.js(8,7): error TS2322: Type 'number[]' is not assignable to type '[number, number]'. Target requires 2 element(s) but source may have fewer. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. range.js(8,7): error TS2322: Type 'number[]' is not assignable to type '[number, number]'. Target requires 2 element(s) but source may have fewer. checked 21 October 2026
/** @param {number[]} prices */
function priceRange(prices) {
  return [Math.min(...prices), Math.max(...prices)];
}

/** @type {[number, number]} */
const range = priceRange([19.5, 12]);error TS2322: Type 'number[]' is not assignable to type '[number, number]'.
  Target requires 2 element(s) but source may have fewer.

export { range };
Without a tuple type, an array literal is an array.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

An array literal is not a tuple

Without a type, return [min, max] is inferred as number[], an array of any length. Assigning that to a [number, number] fails (TS2322, "Target requires 2 element(s) but source may have fewer"), as the third example shows. Declare the tuple on the function with @returns {[number, number]}, or use a const assertion, which makes a read-only tuple.

Element names

Names in a tuple type are documentation: they appear in hovers and completions, and they do not change how you destructure the value. TypeScript added named tuple elements in version 4.0, and optional and rest elements in 3.0.

Gotchas

  • Tuples are still mutable arrays: range.push(3) passes. Make them readonly [number, number] when that matters.
  • Past three or four elements, an object with named properties is easier to read than a tuple.

Questions

How do I return two values from a function with JSDoc types?

Return a tuple and declare it: @returns {[min: number, max: number]}. Callers destructure it, const [low, high] = priceRange(prices).

Sources

Last reviewed 20 October 2026.