TypeScriptエラーの解決策:Cannot assign to 'property' because it is a read-only property

beginner🔵 TypeScript2026-04-06| TypeScript 3.0+, VS Code, Node.js環境

Error Message

Cannot assign to 'property' because it is a read-only property.
#typescript#フロントエンド#web-development#コーディングのヒント

TL;DR: すぐに使える解決策

納期が迫っていますか?コードをすぐに動かすには、以下の3つの方法のいずれかを使用してください。

  • ソースを編集する: インターフェースまたは型定義を探し、readonlyキーワードを削除します。
  • 強制的に変更する: 型アサーションを使用してチェックをバイパスします:(myObject as any).property = 'new value';
  • as constを外す: オブジェクトをas constで定義している場合は、そのサフィックスを削除してオブジェクトを再び変更可能(mutable)にします。

なぜTypeScriptは編集をブロックするのか

このエラーは、コンパイラが明示的に不変(immutable)としてマークされた値を変更しようとする試みを検出したときに発生します。TypeScriptは、予期しない状態変化によるバグを防ぐためにこれを行います。通常、原因は次の3つのシナリオのいずれかです。

  • インターフェースまたは型のプロパティにreadonlyプレフィックスが付いている。
  • オブジェクトがConstアサーションas const)で宣言されており、すべてのフィールドが不変になっている。
  • コンストラクタ以外でreadonlyとマークされたクラスプロパティを更新しようとしている。
interface User {
  readonly id: number;
  name: string;
}

const user: User = { id: 101, name: 'Alice' };
// ❌ エラー: Cannot assign to 'id' because it is a read-only property.
user.id = 202; 

エラーを解決する4つの方法

1. インターフェース定義を変更する

最も簡単な方法は、プロパティの変更を許可することです。retryCountlastLoginタイムスタンプのように、ロジック上で値を更新する必要がある場合、そもそもreadonlyフラグを付けるべきではありません。

// 変更前: 不変(Immutable)
interface AppConfig {
  readonly port: number;
}

// 変更後: 可変(Mutable)
interface AppConfig {
  port: number;
}

2. 型アサーションを使用する(脱出ハッチ)

ソースコードを編集できないサードパーティ製ライブラリを使用している場合に、この問題に遭遇することがあります。このような場合、オブジェクトをキャストすることで、TypeScriptに「自分を信じて」と伝えることができます。これは、特定のデータ状態をモックする必要があるユニットテストでよく使われます。

interface Profile {
  readonly email: string;
}

const userProfile: Profile = { email: 'test@example.com' };

// オプションA: anyにキャストする
(userProfile as any).email = 'new@example.com';

// オプションB: Writableユーティリティ型を作成する
type Writable<T> = { -readonly [P in keyof T]: T[P] };
(userProfile as Writable<Profile>).email = 'admin@internal.com';

3. "as const" アサーションを削除する

as constを使用するのはリテラル型を作成する便利な方法ですが、ネストされたすべてのプロパティをロックしてしまいます。theme設定を'dark'から'light'に変更する必要がある場合は、オブジェクト全体にconstアサーションを使用しないでください。

// このオブジェクトは100%ロックされています
const UI_SETTINGS = {
  theme: 'dark',
  sidebarWidth: 250
} as const;

// UI_SETTINGS.theme = 'light'; // ❌ 失敗します

// 解決策: 標準のオブジェクトまたは特定の型を使用する
const UI_SETTINGS = {
  theme: 'dark',
  sidebarWidth: 250
};

4. Readonly配列を変換する

配列がreadonly string[]として定義されている場合、push()pop()splice()などのメソッドはこのエラーを引き起こします。これらのメソッドは元の配列を変更するため、TypeScriptはそれらをブロックします。これを修正するには、スプレッド演算子を使用して変更可能なコピーを作成します。

const roles: readonly string[] = ['admin', 'editor'];

// roles.push('viewer'); // ❌ エラー

// 解決策: 新しい配列に展開(スプレッド)する
const activeRoles = [...roles];
activeRoles.push('viewer'); // ✅ 正常に動作します

修正内容を再確認する方法

修正を適用したら、次の3つの手順で確認してください。

  • 赤い波線を探す: VS Codeから赤い波線の波線がすぐに消えるはずです。
  • ビルドを実行する: ターミナルを起動し、npx tscを実行します。エラーなしで終了すれば、その修正は型安全です。
  • JSを検証する: as anyを使用した場合は、TypeScriptが実行時に助けてくれないことを忘れないでください。ログやブラウザのコンソールをチェックして、値が実際に更新されたことを確認してください。

プロのヒント: 可能な限り不変(Immutable)を保つ

エラーを消すためだけにreadonlyを削除しないでください。不変性はデバッグを容易にします。ReactやReduxを使用している場合は、読み取り専用プロパティを強制的に変更するのではなく、常に新しいオブジェクトを返してください:const updated = { ...oldObject, status: 'active' };。これにより、データフローの予測可能性が維持され、副作用を避けることができます。

Related Error Notes