TypeScriptでネスト構造クラスを理解する:初心者向けチュートリアル
TypeScriptでネスト構造のクラスを宣言する方法
従来のネスト構造
最も基本的な方法は、従来のネスト構造を用いる方法です。これは、外側のクラス内に内側のクラスを定義する方法です。
class OuterClass {
private innerClass: InnerClass;
constructor() {
this.innerClass = new InnerClass();
}
public someMethod(): void {
this.innerClass.someInnerMethod();
}
}
class InnerClass {
public someInnerMethod(): void {
console.log("Inner method called");
}
}
この方法では、内側のクラスは外側のクラスのメンバ変数として宣言されます。そのため、外側のクラスから内側のクラスに直接アクセスすることができます。
プライベートクラス
TypeScript 3.8以降では、private
キーワードを使用してプライベートなクラスを宣言することができます。プライベートなクラスは、そのクラスを宣言したクラス内からのみアクセスすることができます。
class OuterClass {
private innerClass: InnerClass;
constructor() {
this.innerClass = new InnerClass();
}
public someMethod(): void {
this.innerClass.someInnerMethod();
}
}
private class InnerClass {
public someInnerMethod(): void {
console.log("Inner method called");
}
}
この方法では、内側のクラスは外側のクラスからカプセル化され、外部からのアクセスを防ぐことができます。
名前空間
名前空間を使用すると、グローバルスコープにクラスを宣言することなく、ネスト構造のクラスを定義することができます。
namespace OuterNamespace {
export class InnerClass {
public someInnerMethod(): void {
console.log("Inner method called");
}
}
}
const outerClassInstance = new OuterNamespace.OuterClass();
outerClassInstance.someMethod(); // Inner method called
この方法では、内側のクラスは外側の名前空間に属し、その名前空間を使用してアクセスすることができます。
型エイリアス
型エイリアスを使用すると、ネスト構造のクラスを表す新しい型を定義することができます。
type InnerClassType = {
someInnerMethod(): void;
};
class OuterClass {
private innerClass: InnerClassType;
constructor() {
this.innerClass = {
someInnerMethod: () => console.log("Inner method called"),
};
}
public someMethod(): void {
this.innerClass.someInnerMethod();
}
}
この方法では、内側のクラスの構造を型エイリアスで定義し、その型エイリアスを使用して外側のクラスのメンバ変数を宣言することができます。
使い分け
どの方法を使用するかは、状況によって異なります。
- 内側のクラスの構造を明確に定義したい場合は、型エイリアスを使用します。
- グローバルスコープにクラスを宣言したくない場合は、名前空間を使用します。
- 内側のクラスを外部からカプセル化したい場合は、プライベートクラスを使用します。
- 外側のクラスから内側のクラスに直接アクセスする必要がある場合は、従来のネスト構造を使用します。
- TypeScriptは、型システムを使用してネスト構造のクラスの型安全性を実現することができます。
- ネスト構造のクラスは、継承やインターフェースと同様に、オブジェクト指向プログラミングの設計原則を適用することができます。
class User {
private id: number;
private name: string;
private address: Address;
constructor(id: number, name: string, address: Address) {
this.id = id;
this.name = name;
this.address = address;
}
public getId(): number {
return this.id;
}
public getName(): string {
return this.name;
}
public getAddress(): Address {
return this.address;
}
}
class Address {
private street: string;
private city: string;
private state: string;
private zipCode: string;
constructor(street: string, city: string, state: string, zipCode: string) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public getStreet(): string {
return this.street;
}
public getCity(): string {
return this.city;
}
public getState(): string {
return this.state;
}
public getZipCode(): string {
return this.zipCode;
}
}
const user = new User(1, "John Doe", new Address("123 Main St", "Anytown", "CA", "12345"));
console.log(user.getId()); // 1
console.log(user.getName()); // John Doe
console.log(user.getAddress().getStreet()); // 123 Main St
console.log(user.getAddress().getCity()); // Anytown
console.log(user.getAddress().getState()); // CA
console.log(user.getAddress().getZipCode()); // 12345
class User {
private id: number;
private name: string;
private address: Address;
constructor(id: number, name: string, address: Address) {
this.id = id;
this.name = name;
this.address = address;
}
public getId(): number {
return this.id;
}
public getName(): string {
return this.name;
}
public getAddress(): Address {
return new Address(this.address.street, this.address.city, this.address.state, this.address.zipCode); // コピーを作成して返す
}
}
private class Address {
private street: string;
private city: string;
private state: string;
private zipCode: string;
constructor(street: string, city: string, state: string, zipCode: string) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public getStreet(): string {
return this.street;
}
public getCity(): string {
return this.city;
}
public getState(): string {
return this.state;
}
public getZipCode(): string {
return this.zipCode;
}
}
const user = new User(1, "John Doe", new Address("123 Main St", "Anytown", "CA", "12345"));
console.log(user.getId()); // 1
console.log(user.getName()); // John Doe
console.log(user.getAddress().getStreet()); // 123 Main St
console.log(user.getAddress().getCity()); // Anytown
console.log(user.getAddress().getState()); // CA
console.log(user.getAddress().getZipCode()); // 12345
namespace UserNamespace {
export class User {
private id: number;
private name: string;
private address: Address;
constructor(id: number, name: string, address: Address) {
this.id = id;
this.name = name;
this.address = address;
}
public getId(): number {
return this.id;
}
public getName(): string {
return this.name;
}
public getAddress(): Address {
return new Address(this.address.
匿名クラスを使用すると、名前なしでクラスを定義することができます。これは、短くてシンプルなコードを作成する場合に役立ちます。
class User {
private id: number;
private name: string;
private address: Address;
constructor(id: number, name: string, address: Address) {
this.id = id;
this.name = name;
this.address = address;
}
public getId(): number {
return this.id;
}
public getName(): string {
return this.name;
}
public getAddress(): Address {
return new Address(this.address.street, this.address.city, this.address.state, this.address.zipCode); // コピーを作成して返す
}
}
private class Address {
private street: string;
private city: string;
private state: string;
private zipCode: string;
constructor(street: string, city: string, state: string, zipCode: string) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public getStreet(): string {
return this.street;
}
public getCity(): string {
return this.city;
}
public getState(): string {
return this.state;
}
public getZipCode(): string {
return this.zipCode;
}
}
const user = new User(1, "John Doe", {
street: "123 Main St",
city: "Anytown",
state: "CA",
zipCode: "12345"
});
console.log(user.getId()); // 1
console.log(user.getName()); // John Doe
console.log(user.getAddress().getStreet()); // 123 Main St
console.log(user.getAddress().getCity()); // Anytown
console.log(user.getAddress().getState()); // CA
console.log(user.getAddress().getZipCode()); // 12345
型ガード
型ガードを使用すると、ランタイム時にオブジェクトの型をチェックし、その型に基づいてコードを実行することができます。これは、ネスト構造のクラスにアクセスする際に、より柔軟な制御を行う場合に役立ちます。
class User {
private id: number;
private name: string;
private address: Address;
constructor(id: number, name: string, address: Address) {
this.id = id;
this.name = name;
this.address = address;
}
public getId(): number {
return this.id;
}
public getName(): string {
return this.name;
}
public getAddress(): Address {
return new Address(this.address.street, this.address.city, this.address.state, this.address.zipCode); // コピーを作成して返す
}
}
private class Address {
private street: string;
private city: string;
private state: string;
private zipCode: string;
constructor(street: string, city: string, state: string, zipCode: string) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public getStreet(): string {
return this.street;
}
public getCity(): string {
return this.city;
}
public getState(): string {
return this.state;
}
public getZipCode(): string {
return this.zipCode;
}
}
const user = new User(1, "John Doe", {
street: "123 Main St",
city: "Anytown",
state: "CA",
zipCode: "12345"
});
if (typeof user.getAddress === "function") {
const address: Address = user.getAddress();
console.log(address.getStreet()); // 123 Main St
console.log(address.getCity()); // Anytown
console.log(address.
typescript