1従来の書き方との比較
同じ意味のクラスを、従来の書き方と引数プロパティで並べた例です。constructor(public x: number) {} の1行が、プロパティ宣言・引数の受け取り・this.x = x の3つを兼ねています。まずは「修飾子を付けると引数がプロパティに昇格する」と覚えましょう。
// 従来の書き方: 宣言・受け取り・代入の3点セットが必要
class OldPoint {
x: number;
constructor(x: number) {
this.x = x;
}
}
// 引数プロパティ: public を付けるだけで同じ意味になる
class NewPoint {
constructor(public x: number) {}
}
console.log(new OldPoint(3).x);
console.log(new NewPoint(3).x);
2private 引数プロパティ — 内部状態を1行で作る
private を付ければ「外から見えないプロパティ」が1行で作れます。残高のような内部状態をコンストラクタで受け取りつつ隠す、アクセス修飾子のレッスンでやった設計がさらに短く書けます。外から触れるのはメソッド経由だけ、という形は変わりません。
class Wallet {
// private のプロパティ balance の宣言と代入を兼ねる
constructor(private balance: number) {}
add(amount: number): void {
this.balance = this.balance + amount;
}
current(): number {
return this.balance;
}
}
const wallet = new Wallet(1000);
wallet.add(500);
console.log(wallet.current());
// console.log(wallet.balance); // private なので外からはエラー
3readonly との組み合わせ
引数プロパティには readonly も組み合わせられます。public readonly とすれば「外から読めるが書き換えられない」プロパティになり、ID や確定済みの金額のような作成後に変わってはいけない値にぴったりです。引数が増えたら、このように改行して並べると読みやすくなります。
class OrderRecord {
constructor(
public readonly orderId: string,
public readonly total: number,
) {}
}
const orderRecord = new OrderRecord("A-001", 2480);
console.log(orderRecord.orderId);
console.log(orderRecord.total);
// orderRecord.total = 0; // readonly なので再代入はエラー
4修飾子なしの引数はプロパティにならない
つまずきポイントの確認です。修飾子を付けない width と height はただの引数で、コンストラクタの外には残りません。「コンストラクタの中でだけ使う値」と「プロパティとして持ち続ける値」を、修飾子の有無で書き分けられると整理できます。
class Rectangle {
area: number;
// width / height は修飾子なし = ただの引数。プロパティには残らない
constructor(width: number, height: number, public label: string) {
this.area = width * height;
}
}
const rect = new Rectangle(4, 5, "床面積");
console.log(rect.label + ": " + rect.area);
// console.log(rect.width); // プロパティではないのでエラー
5サービス + DI 風の組み立て
サービスクラスが依存先(MessageStore)をコンストラクタで受け取る、依存性の注入(DI)の典型例です。constructor(private readonly store: MessageStore) {} は、NestJS のコントローラやサービスで毎日見る形そのものです。依存を外から渡す作りにしておくと、テスト時に偽物へ差し替えるのも簡単になります。
class MessageStore {
private messages: string[] = [];
add(body: string): void { this.messages.push(body); }
count(): number { return this.messages.length; }
}
class ChatService {
// 依存を受け取って private readonly プロパティにする(DI の定番)
constructor(private readonly store: MessageStore) {}
post(body: string): void {
this.store.add(body);
console.log("投稿: 合計" + this.store.count() + "件");
}
}
const chatService = new ChatService(new MessageStore());
chatService.post("こんにちは");
chatService.post("引数プロパティ便利!");