TypeScriptエラーの解決: 型 'readonly string[]' の引数を型 'string[]' のパラメーターに割り当てることはできません

中級🔵 TypeScript2026-06-06| TypeScript 3.4+, Node.js, 厳格な型チェックを使用する React/フロントエンドフレームワーク

Error Message

Argument of type 'readonly string[]' is not assignable to parameter of type 'string[]'. The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
#typescript#readonly#配列#型システム#不変性#スプレッド構文

TL;DR: クイック解決策

スプレッド演算子を使用して配列を複製し、ミュータブル(変更可能)なバージョンを作成します。わずか1行で済みます:

const readonlyArray: readonly string[] = ['debug', 'info', 'error'];

// ミュータブルなコピーを作成
processData([...readonlyArray]);

より根本的な修正には、関数のシグネチャを readonly string[] を受け入れるように変更します。これにより、配列のコピーによる不要なメモリ消費を防げます。

本番環境での「深夜2時のシナリオ」

ホットフィックスをデプロイしている最中だとしましょう。ZodやPrisma、あるいは as const で定義された定数などのソースから設定データを取得します。このデータを、これまで何百回と使ってきたユーティリティ関数に渡すと、突然ビルドが失敗します。

Argument of type 'readonly string[]' is not assignable to parameter of type 'string[]'. 
The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.

TypeScriptはここで厳格なボディガードとして振る舞っています。あなたは「決して変更しない」と約束された配列を持っています。しかし、それを変更する権限を持つ関数に渡そうとしています。TypeScriptはそのリスクを見逃しません。

根本原因:契約の不一致

TypeScriptにおいて、string[]Array<string> の略記です。この型には、.push().sort().splice() など、データを直接変更(破壊的変更)するメソッドが含まれています。

readonly string[] 型は異なります。これらは明示的に変更メソッドを取り除いています。もし TypeScript が readonly 配列を標準の string[] を期待する関数に渡すことを許可してしまえば、その関数内で .push('new-item') が呼ばれる可能性があります。それは元のデータの不変性の契約を破ることになります。これは、大規模な状態管理アプリにおいて、デバッグが極めて困難なランタイムバグの原因となります。

解決策

1. 関数のシグネチャを更新する(推奨)

関数が実際に配列を変更しているか確認してください。もし .map().find()、あるいは .length の確認など、データの読み取りのみを行っている場合は、パラメーターの型を変更します。これが最もクリーンな設計上のアプローチです。

// 変更前:
function logMessages(messages: string[]) {
  messages.forEach(m => console.log(m));
}

// 変更後:
function logMessages(messages: readonly string[]) {
  messages.forEach(m => console.log(m));
}

これにより関数はより汎用的になります。ミュータブルな配列とイミュータブルな配列の両方を、エラーなしで扱えるようになります。

2. ミュータブルなコピーを作成する

状況によっては、編集できないレガシーなサードパーティ製ライブラリを使用していることもあるでしょう。関数がデータを .sort() する必要がある場合や、型を変更できない場合は、シャローコピー(浅いコピー)を作成します。

const config: readonly string[] = ['admin', 'user'];

// スプレッド演算子を使用
someExternalLibraryFunction([...config]);

// または古い環境では .slice() を使用
someExternalLibraryFunction(config.slice());

警告:スプレッド構文はシャローコピーしか作成しません。もし配列に1,000個のオブジェクトが含まれている場合、新しい配列もメモリ上の同じ1,000個のオブジェクトを指しています。関数内でオブジェクトのプロパティを変更すると、元のデータにも影響が及びます。

3. 型アサーション(脱出ハッチ)

これを使用するのは、受け取り側の関数がデータを絶対に操作しないと100%確信できる場合のみにしてください。これはコンパイラに「私を信じて」と伝えるもので、TypeScriptを使用する本来の目的である安全チェックをバイパスします。

const data: readonly string[] = fetchData();

// 強制的にミュータブルとして扱う
handleData(data as string[]);

検証ステップ

パイプライン全体で修正が機能することを確認します:

  • コンパイラチェック: npx tsc --noEmit を実行します。ターミナルにエラーが表示されなければ、型エラーは解決されています。
  • メモリ監査: ループ内で5万件以上の要素を持つ配列をコピーしている場合は、メモリ使用量を監視してください。パフォーマンスの観点からは、常にシグネチャの更新(解決策1)が優れています。
  • ロジックテスト: 関数を readonly に更新した場合は、その中で .sort() を使用していないか確認してください。.sort() は元の配列を変更するため、TypeScriptはその関数内で新しいエラーを投げ、.toSorted() の使用やコピーの作成を強制します。

Related Error Notes