TypeScriptのreadonly・optionalプロパティの定義方法を徹底解説!初心者でもわかるクラスの基礎
生徒
「TypeScriptでクラスを勉強していたら、readonlyとかoptionalって出てきたんですけど、これって何ですか?」
先生
「いいところに気づきましたね!これはクラスのプロパティを定義するときに便利な仕組みで、プログラムの安全性や使いやすさを高めてくれるんです。」
生徒
「なるほど。でも、どういうときに使うんでしょうか?」
先生
「それでは、readonlyとoptionalプロパティについて、順番に具体例を見ながら学んでいきましょう!」
1. readonlyプロパティとは?
readonlyプロパティは、一度値を設定すると変更できないプロパティのことです。英語の「read(読む)」と「only(だけ)」を組み合わせた言葉で、つまり「読み取り専用」という意味です。
例えば、学生の「学籍番号」を考えてみましょう。学籍番号は一度決まったら途中で変わることはありません。このように「変えてはいけない情報」を扱うときに、readonlyを使うと安心です。
class Student {
readonly studentId: number;
name: string;
constructor(studentId: number, name: string) {
this.studentId = studentId;
this.name = name;
}
}
const s = new Student(101, "太郎");
console.log(s.studentId); // 読み取りはOK
// s.studentId = 200; // エラー!readonlyなので変更できない
101
この例では、studentIdにreadonlyをつけているので、作成時に設定した番号はそのまま固定されます。もし間違って変更しようとするとエラーになり、プログラムの不具合を未然に防ぐことができます。
2. optionalプロパティとは?
optionalプロパティは「なくても良いプロパティ」のことです。TypeScriptでは、プロパティ名のあとに?(クエスチョンマーク)をつけると、値を指定してもしなくても良いようにできます。
例えば、ユーザーのプロフィールを考えてみましょう。ユーザーによっては「電話番号」を登録していない場合もあります。このとき「電話番号は必須ではない」としたいなら、optionalを使うと便利です。
class User {
name: string;
phoneNumber?: string; // optional(あってもなくても良い)
constructor(name: string, phoneNumber?: string) {
this.name = name;
this.phoneNumber = phoneNumber;
}
}
const u1 = new User("花子", "090-1234-5678");
console.log(u1.name, u1.phoneNumber);
const u2 = new User("次郎");
console.log(u2.name, u2.phoneNumber); // undefined
花子 090-1234-5678
次郎 undefined
このように、phoneNumberをoptionalにすることで、入力がない場合は自動的にundefinedになります。「必須ではない情報」を扱うときにoptionalは欠かせません。
3. readonlyとoptionalを組み合わせる
実際の開発では、readonlyとoptionalを組み合わせて使うこともできます。例えば、商品データを考えてみましょう。
商品には必ず「商品ID」が必要ですが、これは一度決まったら変わりません。そこでreadonlyを使います。一方で「割引率」などは存在しない場合もあるのでoptionalにできます。
class Product {
readonly productId: number;
name: string;
discountRate?: number; // optional
constructor(productId: number, name: string, discountRate?: number) {
this.productId = productId;
this.name = name;
this.discountRate = discountRate;
}
}
const p1 = new Product(1, "ノートPC", 10);
console.log(p1);
const p2 = new Product(2, "スマートフォン");
console.log(p2);
Product { productId: 1, name: 'ノートPC', discountRate: 10 }
Product { productId: 2, name: 'スマートフォン' }
このように、プロパティの性質に合わせてreadonlyとoptionalを適切に使い分けることで、プログラムの設計が明確になり、エラーの少ないコードを書くことができます。
4. readonlyとoptionalを使うメリット
ここで、初心者が覚えておきたいメリットを整理しましょう。
- readonlyは、値を固定することで「間違った代入を防げる」。
- optionalは、柔軟に「なくてもいいデータ」を扱える。
- 組み合わせることで「必須で固定の情報」と「任意の情報」を両方表現できる。
- クラスを設計するときに、実際の現実世界のルール(変わらないもの・あってもなくても良いもの)をうまくプログラムに反映できる。
この考え方は、TypeScriptのオブジェクト指向プログラミングにおいて非常に重要です。初心者でも、現実の例に置き換えて考えれば理解しやすくなるでしょう。
まとめ
TypeScriptのクラスで扱うreadonlyプロパティとoptionalプロパティは、初心者が特に理解しておきたい重要な基礎です。readonlyは一度だけ値を設定できる性質を持ち、学籍番号や商品IDのように変更が許されない情報を確実に守るために役立ちます。プログラム設計では、間違った代入が原因になる不具合を早い段階で防ぐことができるため、読み取り専用の性質を持つ値はreadonlyと組み合わせると安全なコードになります。さらにoptionalプロパティは、値が存在しなくても問題が起きない柔軟な仕組みを与えてくれます。電話番号や割引率のように「必須でない情報」を扱うときに、optionalは自然な設計を可能にします。値がないときには自動的にundefinedになり、undefinedを前提とした安全な実装ができることは大きなメリットです。 また、readonlyとoptionalは単体で使うだけではなく、組み合わせることでより現実に即したモデリングが可能になります。商品データの例でいえば、商品IDのように絶対に変わらない情報にはreadonlyを、割引情報のように商品によって有無が変わるものにはoptionalを設定することで、柔軟でありながら誤りのないデータ構造を作り出すことができます。実際のアプリケーションでも、必須項目・任意項目を分けて管理する場面は頻繁にあります。そんなときに、クラスのプロパティに適切な性質を与えることができれば、開発全体の品質向上につながっていきます。 特に初心者は、クラスを設計するときに全てのプロパティを同じように扱いがちですが、値の性質によってreadonlyやoptionalを付け分けることで、より明確で安全なコードになります。プロパティをどのような意図で定義しているかが明確になると、クラスを使う側も誤った使い方をしにくくなり、コード全体の保守性が高まります。これは、オブジェクト指向の基礎「現実世界のルールをプログラムへ正しく写す」という考え方にも強く結びついています。
サンプルプログラムの振り返り
ここでは、readonlyとoptionalを組み合わせたサンプルをもう一つ確認しておきましょう。商品データを扱うクラスを再設計すると、次のような書き方もできます。
class Item {
readonly itemId: number;
name: string;
description?: string;
price: number;
constructor(
itemId: number,
name: string,
price: number,
description?: string
) {
this.itemId = itemId;
this.name = name;
this.price = price;
this.description = description;
}
}
const itemA = new Item(1001, "バックパック", 5800, "軽量で丈夫なモデル");
const itemB = new Item(1002, "ボールペン", 120);
console.log(itemA, itemB);
このコードでは、itemIdはreadonlyにすることで変更できない情報として扱い、descriptionはoptionalとして任意項目にしています。descriptionのような説明文は商品によってある場合とない場合があるためoptionalにするのが自然です。商品名や価格のように必須で変更できる値は通常のプロパティとして定義し、用途に応じてプロパティに適切な性質を与えることで分かりやすいクラスになります。読み取り専用の情報と柔軟に扱う情報を整理して設計していくことで、初心者でも実践しやすいデータ構造が作れることが分かるはずです。
プロパティ設計がアプリ開発に与える影響
クラスのプロパティをどのように定義するかは、その後のアプリ全体の動きに大きく影響します。readonlyを使えば一貫性のあるデータが確保され、optionalを使えば柔軟な入力や不完全な情報を許容できるようになります。特にユーザー情報・商品データ・予約データなど、現実世界のさまざまな情報を扱う場面では、「変わるもの」「変わらないもの」「あってもなくても良いもの」を整理して設計することが非常に重要です。プロパティの性質を理解して正しく使い分けることで、アプリはより安全で扱いやすくなり、後から機能追加を行うときも整った形で拡張できます。 また、開発においては他の人が書いたクラスを利用する機会も多くあります。その際、readonlyやoptionalが付いているかどうかでそのクラスの使い方や意図が明確に分かるため、チーム開発においてもコミュニケーションコストを下げる効果があります。初心者のうちから、プロパティの性質を見極める感覚を身につけておくことは、今後のスキルアップにも確実につながります。
生徒
「readonlyとoptionalって、ただの記号みたいに思っていたけど、役割がはっきりしていて便利なんだって分かりました!」
先生
「そうですね。プロパティに意味を持たせることで、プログラム全体が理解しやすくなりますし、間違いも防げます。」
生徒
「特にreadonlyで間違って書き換えられないようにするのは安心ですね。optionalもうまく使えば柔軟な設計になるんですね。」
先生
「その通りです。現実のデータの特徴に合わせてreadonlyやoptionalを使い分けられるようになれば、クラス設計はぐっと上達しますよ。」