TypeScriptのgetとsetアクセサについて
TypeScriptにおけるgetとset
TypeScriptでは、クラスのプロパティに対するアクセス制御やデータバリデーションのために、get
とset
アクセサを使用することができます。
get
アクセサ
- 計算された値や、内部状態に基づいて値を返すことができます。
- 読み取り専用プロパティを実現できます。
- プロパティの値を取得するためのメソッドです。
例
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name(): string {
return this._name;
}
}
この例では、name
プロパティはプライベートであり、get
アクセサを通じて外部から読み取ることができますが、直接書き込むことはできません。
- データバリデーションや、内部状態の更新を行うことができます。
class Rectangle {
private _width: number;
private _height: number;
constructor(width: number, height: number) {
this._width = width;
this._height = height;
}
get area(): number {
return this._width * this._height;
}
set width(value: n umber) {
if (value < 0) {
throw new Error("Width cannot be negative");
}
this._width = value;
}
set height(value: number) {
if (value < 0) {
throw new Error("Height cannot be negative");
}
this._height = value;
}
}
この例では、width
とheight
プロパティはプライベートであり、set
アクセサを通じて外部から書き込むことができます。ただし、値が負の場合にはエラーをスローします。
get
アクセサは読み取り専用プロパティを実現し、set
アクセサは書き込み専用プロパティを実現します。get
とset
アクセサは、プロパティに対するアクセス制御やデータバリデーションを実現するために使用されます。
TypeScriptのgetとsetアクセサの例コード解説
Personクラスの例
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name(): string {
return this._name;
}
}
- get name(): string { ... }
name
という名前のゲッターを定義しています。- このゲッターは、
_name
プロパティの値を返します。 - 外部から
person.name
とアクセスすると、このゲッターが呼び出され、_name
の値が取得されます。
- private _name: string;
_name
という名前のプライベートな文字列型のプロパティを定義しています。- プライベートプロパティは、クラスの内部からしか直接アクセスできません。
この例の意味
_name
という内部的なプロパティで名前を保持し、name
という公開的なインターフェースでアクセスできるようにしています。Person
クラスのname
プロパティは、外部から読み取りは可能ですが、書き込みはできません。
Rectangleクラスの例
class Rectangle {
private _width: number;
private _height: number;
constructor(width: number, height: number) {
this._width = width;
this._height = height;
}
get area(): number {
return this._width * this._height;
}
set width(value: n umber) {
if (value < 0) {
throw new Error("Width cannot be negative");
}
this._width = value;
}
set height(value: number) {
if (value < 0) {
throw new Error("Height cannot be negative");
}
this._height = value;
}
}
- set height(value: number) { ... }
height
プロパティのセッターも同様に、値のバリデーションを行い、_height
プロパティに値を代入します。
- set width(value: number) { ... }
- このセッターは、
width
プロパティに値を設定する際に呼び出されます。 - 値が負の場合にはエラーをスローし、正の値の場合には
_width
プロパティに値を代入します。
- このセッターは、
- get area(): number { ... }
- これは、
width
とheight
のプロパティに基づいて長方形の面積を計算し、その値を返します。
- これは、
- 外部から
rectangle.width = 10
のように値を設定すると、width
セッターが呼び出され、値のバリデーションが行われます。 area
は計算されたプロパティであり、直接値を設定することはできません。Rectangle
クラスでは、width
とheight
のプロパティに値を設定する際に、負の値が設定されないようにバリデーションを行っています。
- プライベートプロパティと組み合わせて使用することで、カプセル化を実現できます。
- アクセサを使用することで、プロパティに対するアクセスを制御し、データの整合性を保つことができます。
TypeScriptのgetとsetアクセサは、クラスの設計において非常に重要な役割を果たします。これらの機能を理解することで、より安全で保守性の高いコードを書くことができるようになります。
- アクセサはジェネリクスと組み合わせることができる
より柔軟なアクセサを定義することができます。 - アクセサはオーバーライドできる
派生クラスでアクセサをオーバーライドすることで、基底クラスのアクセサの動作を変更できます。 - アクセサは継承される
基底クラスで定義されたアクセサは、派生クラスでも使用できます。
メソッドによる実装
- 複雑なロジック
- シンプルなプロパティ
- ゲッターとセッターの代わりに、
getXXX()
とsetXXX()
という名前のメソッドを定義する方法です。 - これは、アクセサよりも直接的で、シンプルなプロパティのように扱えます。
- ゲッターとセッターの代わりに、
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
getName(): string {
return this._name;
}
setName(name: string) {
th is._name = name;
}
}
Object.defineProperty
- 動的なプロパティ
- 詳細な制御
- JavaScriptの組み込みオブジェクトである
Object.defineProperty
を使用することで、プロパティのアクセサーをより詳細に定義できます。 - 構成可能なプロパティ、列挙可能なプロパティなど、さまざまな属性を設定できます。
- JavaScriptの組み込みオブジェクトである
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
Object.defineProperty(this, 'name', {
get: () => { return this._name; },
set: (value) => { this._name = value; }
});
}
}
Computed Properties
- 動的なプロパティ名
- テンプレート文字列を使用して、動的にプロパティ名を生成できます。
- 複雑なオブジェクト構造を扱う場合に便利です。
class Data {
[key: string]: any;
setData(key: string, value: any) {
this[key] = value;
}
getData(key: string) {
return this[key];
}
}
プライベートフィールド
- 簡潔な記述
- アクセサーよりも簡潔に記述できます。
- TypeScript 3.8以降
- プライベートフィールドが導入されました。
- アクセサーを使用せずに、プライベートなプロパティを直接定義できます。
class Person {
#name: string;
constructor(name: string) {
this.#name = name;
}
}
どの方法を選ぶべきか?
- TypeScript 3.8以降で、シンプルなプライベートプロパティが必要な場合
プライベートフィールドを使用します。 - 動的なプロパティが必要な場合
Computed Propertiesを使用します。 - 詳細な制御が必要な場合
Object.defineProperty
を使用します。 - シンプルで一般的なケース
ゲッターとセッターが最も直感的で、多くの場合に適しています。
選択のポイント
- パフォーマンス
特に大規模なアプリケーションでは、パフォーマンスが重要な要素となる場合がある。 - 柔軟性
必要な機能を満たせるか。 - 可読性
コードの読みやすさを考慮する。
typescript