できない.dev

TypeScript で readonly 配列に push できず Property does not exist になり変更できない

readonly T[] / ReadonlyArray<T> / as const で得た配列はミューテーション系メソッド(push / pop / sort 等)の型を持たないため、変更しようとすると型エラーになります。
スプレッドで可変コピーを作るか、可変な型に再宣言するのが基本対処です。

公開: 更新:

要約

Property 'push' does not exist on type 'readonly number[]' のようなエラーは、readonly T[] / ReadonlyArray<T> / as const の配列が変更系メソッドを型レベルで持たないために出ます。
値を変更したい場合はスプレッドや Array.from で可変コピーを作り、それを書き換えるのが基本です。
不変性を保ちたいなら新しい配列を返す関数型の書き方に切り替えます。

よくある原因

  1. 変数や引数の型を readonly T[] / ReadonlyArray<T> で宣言している
  2. リテラルに as const を付けたため、配列が readonly [...] タプル型になっている
  3. ライブラリ関数が ReadonlyArray<T> を返しており、その結果に push しようとしている
  4. Object.freeze 由来で型が readonly 化されている

解決策

1. スプレッドで可変コピーを作る

const nums: readonly number[] = [1, 2, 3];
const mutable = [...nums];
mutable.push(4);

Array.from(nums) でも同じ結果が得られます。
元配列の不変性を保ったまま、新しい配列だけ操作できます(公式ハンドブック(新しいタブで開く))。

2. 不変にする意図が無いなら型注釈を変える

// 変更前
const xs: readonly number[] = [1, 2, 3];
xs.push(4); // ERROR
 
// 変更後
const xs: number[] = [1, 2, 3];
xs.push(4); // OK

3. as const を外すか、入れ子だけに使う

const colors = ["red", "green", "blue"] as const;
colors.push("yellow"); // ERROR: as const でタプル化された配列
 
const colors2 = ["red", "green", "blue"];
colors2.push("yellow"); // OK: string[]
 
type Color = "red" | "green" | "blue";
const colors3: Color[] = ["red", "green", "blue"];
colors3.push("yellow"); // ERROR: "yellow" は Color ではない

4. 関数 API は readonly 受け取り・呼び出し側でコピー

引数を readonly T[] で受け取ると、関数の中で誤って書き換える事故を型で防げます。
書き換えたい場合は呼び出し側で slice() してから渡します。

function append(xs: readonly number[], x: number): number[] {
  return [...xs, x];
}
 
const a = [1, 2, 3];
const b = append(a, 4);

不変性を維持しつつ「変更後の配列」を返す関数型の書き方は、Redux / Zustand / Recoil などの状態管理ともよく合います。

実行例

実際に上記の手順を node:20 環境で動かすと、readonly number[] に対して push を呼び出した時点で error TS2339: Property 'push' does not exist on type 'readonly number[]' が出力され tsc が終了コード 2 で終了し、スプレッドによる可変コピーへ切り替えた後は終了コード 0 となり解消が確認できます。

Version 5.9.3
$ npx tsc
src/bad.ts(2,6): error TS2339: Property 'push' does not exist on type 'readonly number[]'.
tsc の終了コード: 2
$ npx tsc
tsc の終了コード: 0(0 なら解消)

— 2026-08-02 時点の出力

この記事は役立ちましたか?