A read-only array type, {readonly string[]} or {ReadonlyArray<string>}, has every array method that does not change the array (map, filter, slice, indexing) and none that does (push, splice, sort, index assignment). Calling one is an error (TS2339), as the first example shows.
It is most useful on parameters. @param {readonly string[]} sizes tells callers that the function will not modify their array, and TypeScript holds the function to it. Ordinary arrays can be passed where a readonly array is expected.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| A read-only array | /** @param {readonly string[]} sizes */ | (sizes: readonly string[]) |
| Generic spelling | /** @param {ReadonlyArray<string>} sizes */ | (sizes: ReadonlyArray<string>) |
| A read-only tuple | /** @type {readonly [number, number]} */ | : readonly [number, number] |
Examples
/** @param {readonly string[]} sizes */
export function withXL(sizes) {
sizes.push("XL");error TS2339: Property 'push' does not exist on type 'readonly string[]'.
return sizes;
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @param {readonly string[]} sizes
* @returns {string[]}
*/
export function sortedSizes(sizes) {
return [...sizes].sort();
}
/** @param {ReadonlyArray<number>} prices */
export function cheapest(prices) {
return Math.min(...prices);
}
const sizes = ["L", "S", "M"];
sortedSizes(sizes);
cheapest([19.5, 12]);export function sortedSizes(sizes: readonly string[]): string[] {
return [...sizes].sort();
}
export function cheapest(prices: ReadonlyArray<number>) {
return Math.min(...prices);
}
const sizes = ["L", "S", "M"];
sortedSizes(sizes);
cheapest([19.5, 12]);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Working with them
To sort or extend, copy first: [...sizes].sort() returns a new, mutable string[]. Methods that already return new arrays, such as map and filter, work directly.
TypeScript added the readonly array syntax in version 3.4. A const assertion on an array literal, /** @type {const} */ (["S", "M"]), produces a read-only tuple.
Gotchas
- Read-only exists only in the types: TypeScript checks it, the running code does not.
Object.freeze(array)makes it read-only at run time as well, and TypeScript types the result asreadonly T[]. - A
readonly string[]cannot be passed where a mutablestring[]is expected, because the receiver might change it. Mark parameters readonly from the bottom up.
Questions
What is the difference between readonly string[] and ReadonlyArray<string>?
None; they are two spellings of the same type.
Sources
- TypeScript 3.4: improvements for ReadonlyArray and readonly tuples · TypeScript release notes
- Object Types: the ReadonlyArray type · TypeScript handbook
Last reviewed 20 October 2026.