TypeScriptのreadonly修飾子の使い方を完全ガイド!初心者でもわかる変更不可プロパティ
生徒
「TypeScriptで、一度決めた値を変更できなくする方法ってありますか?」
先生
「はい、それにはreadonly(リードオンリー)という修飾子を使います。変更できないプロパティを作ることができますよ。」
生徒
「なるほど!具体的にどんな時に使うんですか?」
先生
「では、readonlyの基本から、使い方や注意点まで詳しく見ていきましょう!」
1. readonly修飾子とは?
readonly(リードオンリー)とは、英語の「読み取り専用」を意味し、TypeScriptでは一度だけ値を設定できるプロパティを作るために使います。いったん値が決まった後は変更できなくなるため、データの整合性を守るための仕組みとしてとても重要です。
たとえば、ユーザーID・登録日時・製品コードなど、アプリの中で絶対に変わってはいけない情報に使われます。誤って値を上書きしてしまうトラブルを防ぎ、安全にデータを扱うための“ロック”のような役割だと考えると分かりやすいでしょう。
まずは、readonlyがどのように働くのか、簡単な例を見てみましょう。
interface User {
readonly id: number;
name: string;
}
const user: User = {
id: 1,
name: "太郎"
};
// OK:nameは変更可能
user.name = "次郎";
// NG:idはreadonlyなので変更不可
user.id = 2;
このように、readonlyを付けるだけで、意図しない変更を防ぎ、より信頼性の高いデータ管理ができるようになります。初心者でもすぐに使い始められる便利な仕組みなので、プロパティを守りたいときに積極的に取り入れてみましょう。
2. readonlyの基本的な使い方
readonlyは、オブジェクトのプロパティに「ここは変更できませんよ」という制限をかけるための仕組みです。特に、誤って値を書き換えてしまうミスを防ぐことができるため、TypeScriptで安全なコードを書くうえで非常に役立ちます。まずは、どのように使うのか具体例を見てみましょう。
interface User {
readonly id: number; // 読み取り専用
name: string; // 通常のプロパティ
}
const user: User = {
id: 1,
name: "太郎"
};
// OK:nameは変更可能
user.name = "次郎";
// NG:idはreadonlyなので変更できない
user.id = 2;
この例では、idにreadonlyが付いているため、オブジェクト生成時(初期化時)に設定した値から変更することはできません。一方で、nameには制限がないので自由に上書きできます。初心者がつまずきやすい「誤った代入」によるバグを防ぐうえで、readonlyはとても強力です。
実行結果(コンパイルエラー):
Cannot assign to 'id' because it is a read-only property.
このように、TypeScriptはエラーで教えてくれるため、コードをより安全に保つことができます。「変更してはいけない値」を守りたい時は、迷わずreadonlyを使うのが良いでしょう。
3. クラスでのreadonlyの使い方
class(クラス)でも、readonlyを使うことができます。主に、constructor(コンストラクタ)という初期化用の関数で値をセットします。
class Product {
readonly code: string;
constructor(code: string) {
this.code = code;
}
}
const product = new Product("ABC123");
// この操作はエラー
product.code = "XYZ789";
constructorで一度だけ値をセットして、その後は変更できないようになります。
4. readonlyを配列に使う場合
readonlyは、配列にも使うことができます。変更不可な配列(読み取り専用の配列)を作りたいときに便利です。
const colors: readonly string[] = ["red", "green", "blue"];
// この操作はエラー
colors.push("yellow");
// この操作もエラー
colors[0] = "black";
readonly string[]と書くことで、配列に対する変更操作(pushやspliceなど)も禁止されます。
5. readonlyとconstの違いは?
readonlyとよく似たものにconstがありますが、用途が違います。
constは変数に使う(再代入を禁止)readonlyはオブジェクトやクラスのプロパティに使う(プロパティの再代入を禁止)
const user = {
name: "花子"
};
// オブジェクト自体は定数でも
user.name = "さくら"; // これはOK
Object.freeze(user); // これはJavaScriptの書き方で完全に凍結する方法
constで定義しても、オブジェクトの中身は変更できてしまうことがあるため、readonlyを使ってプロパティ単位で制限するのがポイントです。
6. readonlyの注意点
readonlyは「完全な変更禁止」ではありません。あくまで「再代入が禁止されるだけ」です。
たとえば、オブジェクトの中にある別のオブジェクトや配列は、変更可能な場合があります。
interface Data {
readonly list: string[];
}
const data: Data = {
list: ["A", "B"]
};
// これはOK(listの中身は変えられる)
data.list.push("C");
このように、「中の中」まで変更禁止にしたい場合は、さらに深い制御が必要になります。
7. readonlyをうまく使う場面
TypeScriptでreadonlyを使うことで、安全で間違いの少ないコードを書くことができます。
次のようなケースでは、特にreadonlyの活用がおすすめです:
- ユーザーIDや製品コードなど、絶対に変えてはいけない情報
- ログイン時間など、一度設定されたら記録として残したい情報
- システム設定など、外部から書き換えられたくないデータ
readonlyを使うことで、「うっかりミス」によるバグを防ぐことができます。
まとめ
TypeScriptでプロパティを保護するときに活躍するのがreadonly修飾子でした。この修飾子を使うことで、一度決めた値をまちがって更新してしまうようなミスを防ぐことができます。
readonlyを使えば、コードに意図を明確に伝えることができます。「この情報は保持したい、誰も更新してはいけない」という意図は、大規模な開発や互換の多いコードで特に重要です。ここで、readonlyを搭載したサンプルを一つ紹介しましょう。
readonlyでユーザー情報を守る例
interface Account {
readonly userId: number;
readonly createdAt: Date;
nickname: string;
}
const account: Account = {
userId: 101,
createdAt: new Date("2023-01-01"),
nickname: "hana"
};
account.nickname = "momo"; // OK
account.userId = 202; // エラー
この例ではuserIdやcreatedAtにreadonlyを付けているため、後からの値の変更を禁止できています。一方、nicknameは単なる文字列なので更新することも可能です。
readonlyを使う場合の別の例として、配列やクラスのプロパティも対象になることを忘れずに。配列につけたreadonlyは、配列の値の上書きや配列操作を禁止するものとなり、コードの符号対象をあらかじめ安定化させるテクニックに組み込めます。
生徒
「readonlyって、値が変わっちゃいけないものを守るときにとても便利なんですね。」
先生
「そうです。同じ型のデータでも、変更可能なものと禁止されたものが明確になるのは、コードを読む側にとっても大切ですよ。」
生徒
「クラスのプロパティや配列にもreadonlyが使えるって、使い手段が広がりますね。」
先生
「そうですね。これからは、『変更してはいけないもの』は必ずreadonlyを付けて、意図を明確に伝えることを意識していきましょう。」