constとreadonlyを使いこなして、より安全で堅牢なTypeScriptコードを書こう
TypeScriptにおけるconstとreadonlyの違い
const
constは、変数自体への再代入を禁止します。つまり、constで宣言した変数に新しい値を代入することはできません。
const name = "John Doe";
name = "Jane Doe"; // エラー: 'name' は const であるため再代入できません
constで宣言した変数は、プリミティブ型(文字列、数値、ブール値など)だけでなく、オブジェクトや配列にも使用できます。
const person = {
name: "John Doe",
age: 30,
};
person.name = "Jane Doe"; // 許可されます
上記の例では、person
変数はconstで宣言されていますが、person.name
プロパティへの変更は許可されています。これは、constが変数自体への再代入のみを禁止するためです。
readonly
readonlyは、プロパティへの変更を禁止します。つまり、readonlyで修飾されたプロパティに新しい値を代入することはできません。
interface Person {
readonly name: string;
age: number;
}
const person: Person = {
name: "John Doe",
age: 30,
};
person.name = "Jane Doe"; // エラー: 'name' は readonly であるため変更できません
上記の例では、name
プロパティはreadonlyで修飾されています。そのため、person.name
に新しい値を代入しようとすると、エラーが発生します。
readonlyは、オブジェクトのプロパティを保護したい場合に便利です。例えば、データベースから取得したデータを表すオブジェクトを作成する場合、そのプロパティを誤って変更してしまうことを防ぐためにreadonlyを使用できます。
機能 | const | readonly |
---|---|---|
対象 | 変数 | プロパティ |
制限 | 再代入 | 変更 |
使用例 | プリミティブ型、オブジェクト、配列 | オブジェクトのプロパティ |
どちらを使用するべきか?
一般的には、以下のルールに従うと良いでしょう。
- オブジェクトの一部プロパティのみを変更しない場合は、readonly修飾子を個別にプロパティに付与する。
- オブジェクトのプロパティを変更しない場合は、readonlyを使用する。
- 変数自体を変更しない場合は、constを使用する。
const name = "John Doe"; // 文字列リテラル
const age = 30; // 数値リテラル
const isAdult = true; // ブールリテラル
const person = {
name: "John Doe",
age: 30,
};
person.name = "Jane Doe"; // 許可されます
const numbers: number[] = [1, 2, 3];
numbers.push(4); // 許可されます
interface Person {
readonly name: string;
age: number;
}
const person: Person = {
name: "John Doe",
age: 30,
};
person.name = "Jane Doe"; // エラー: 'name' は readonly であるため変更できません
const numbers: readonly number[] = [1, 2, 3];
numbers.push(4); // エラー: 'numbers' は readonly であるため変更できません
組み合わせ
const person: {
readonly name: string;
age: number;
} = {
name: "John Doe",
age: 30,
};
person.age = 31; // 許可されます
const numbers: readonly number[] = [1, 2, 3];
// 'numbers' は readonly であるため、新しい配列を作成する必要があります
const newNumbers = [...numbers, 4];
constとreadonly以外の方法
オブジェクトのフリーズ
Object.freeze()
メソッドを使用して、オブジェクトを不可変更にすることができます。
const person = {
name: "John Doe",
age: 30,
};
Object.freeze(person);
person.name = "Jane Doe"; // エラー: 'person' は凍結されているため変更できません
プロパティアクセサ
プロパティアクセサを使用して、プロパティへのアクセスを制御することができます。
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name() {
return this._name;
}
set name(newName: string) {
if (newName === this._name) {
return;
}
this._name = newName;
}
}
const person = new Person("John Doe");
person.name = "Jane Doe"; // 許可されます
console.log(person.name); // "Jane Doe"
イミュータブルライブラリ
immutable.js
などのライブラリを使用して、イミュータブルなデータ構造を扱うことができます。
import { Map } from "immutable";
const person = Map({
name: "John Doe",
age: 30,
});
const newPerson = person.set("name", "Jane Doe");
console.log(person.get("name")); // "John Doe"
console.log(newPerson.get("name")); // "Jane Doe"
これらの方法は、const and readonly と比べてより柔軟な制御を提供できます。ただし、コードが複雑になる可能性があります。
typescript