MeWrite Docs

Cannot assign to 'x' because it is a read-only property

TypeScriptで読み取り専用プロパティに代入しようとした場合のエラー

概要

Cannot assign to 'x' because it is a read-only property は、TypeScriptで readonly 修飾子が付いたプロパティや、Readonly<T> 型のオブジェクトのプロパティに値を代入しようとした場合に発生するコンパイルエラーです。

エラーメッセージ

error TS2540: Cannot assign to 'name' because it is a read-only property.
error TS2540: Cannot assign to '0' because it is a read-only property.

原因

1. readonly プロパティへの代入

1
2
3
4
5
6
7
interface User {
  readonly id: number;
  name: string;
}

const user: User = { id: 1, name: 'John' };
user.id = 2; // Error: Cannot assign to 'id'

2. Readonly 型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
interface Config {
  apiUrl: string;
  timeout: number;
}

const config: Readonly<Config> = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};

config.apiUrl = 'https://new.example.com'; // Error

3. ReadonlyArray

1
2
3
const numbers: ReadonlyArray<number> = [1, 2, 3];
numbers[0] = 10; // Error
numbers.push(4); // Error: Property 'push' does not exist

4. as const アサーション

1
2
3
4
5
6
const config = {
  api: 'https://api.example.com',
  timeout: 5000
} as const;

config.api = 'new'; // Error

解決策

1. 新しいオブジェクトを作成

1
2
3
4
5
6
7
8
9
interface User {
  readonly id: number;
  name: string;
}

const user: User = { id: 1, name: 'John' };

// 新しいオブジェクトを作成
const updatedUser: User = { ...user, id: 2 };

2. readonly を削除(設計を見直す)

1
2
3
4
5
// 変更が必要な場合は readonly を外す
interface User {
  id: number; // readonly を削除
  name: string;
}

3. Mutableユーティリティ型を作成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

interface Config {
  readonly apiUrl: string;
  readonly timeout: number;
}

// 変更可能な型を作成
const mutableConfig: Mutable<Config> = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};

mutableConfig.apiUrl = 'new'; // OK

4. 配列の場合

1
2
3
4
5
6
7
8
9
const numbers: readonly number[] = [1, 2, 3];

// 新しい配列を作成
const newNumbers = [...numbers, 4]; // OK
const filtered = numbers.filter(n => n > 1); // OK(新しい配列を返す)

// または明示的にミュータブルな配列を使用
const mutableNumbers: number[] = [...numbers];
mutableNumbers.push(4); // OK

5. クラスでの readonly

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class User {
  readonly id: number;
  name: string;

  constructor(id: number, name: string) {
    this.id = id; // constructorでは代入可能
    this.name = name;
  }

  // メソッドで変更が必要な場合は新しいインスタンスを返す
  withId(newId: number): User {
    return new User(newId, this.name);
  }
}

イミュータブルパターン

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Immer ライブラリを使用
import produce from 'immer';

interface State {
  readonly users: readonly User[];
}

const nextState = produce(state, draft => {
  draft.users.push({ id: 1, name: 'John' }); // 内部的にコピーを作成
});

関連エラー

関連エラー

TypeScript の他のエラー

最終更新: 2025-12-17