TypeScriptでクラスを定義する基本的な方法と実例解説

TypeScriptは、JavaScriptの拡張であり、静的型付けとオブジェクト指向プログラミング(OOP)の概念を取り入れています。その中でもクラスは、コードの再利用性と可読性を向上させる重要な機能です。本記事では、TypeScriptにおけるクラスの基本的な定義方法や使い方について、初心者向けにわかりやすく解説していきます。TypeScriptのクラスを理解することで、より効率的に大型のアプリケーションを開発できるようになります。

目次

TypeScriptにおけるクラスの基本概念

TypeScriptのクラスは、オブジェクト指向プログラミングの基本要素であり、オブジェクトを生成するためのテンプレートです。クラス内には、データを表すプロパティと、データを操作するためのメソッドが定義されます。

クラスの定義

クラスを定義するには、classキーワードを使用します。以下は、基本的なクラスの定義例です。

class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    greet(): void {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

この例では、Personクラスが定義されており、nameageというプロパティ、greetというメソッドが含まれています。クラス内のメソッドは、クラスインスタンスが持つデータにアクセスでき、動作をカプセル化します。

プロパティとメソッド

  • プロパティ: クラスが持つデータ(例: nameage)。
  • メソッド: クラスが提供する機能(例: greet())。

このように、クラスは関連するデータと機能を1つのまとまりとして扱い、プログラムの構造を整理するために役立ちます。

クラスのコンストラクタ

クラスのコンストラクタは、クラスのインスタンスが生成される際に自動的に呼び出される特別なメソッドです。コンストラクタは、オブジェクトの初期状態を設定するために使用され、主にプロパティの初期化を行います。

コンストラクタの役割

コンストラクタは、クラスのインスタンスが作成される際に実行され、インスタンスごとに異なるプロパティの値を設定するために利用されます。次の例を見てみましょう。

class Person {
    name: string;
    age: number;

    // コンストラクタ
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    greet(): void {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

// インスタンスの生成
const person1 = new Person('Alice', 30);
person1.greet(); // "Hello, my name is Alice and I am 30 years old."

この例では、Personクラスにコンストラクタが定義されています。newキーワードを使ってPersonのインスタンスを作成すると、自動的にコンストラクタが呼び出され、nameageプロパティが初期化されます。

デフォルトコンストラクタ

もしコンストラクタを明示的に定義しない場合、TypeScriptはデフォルトの空のコンストラクタを自動で提供します。しかし、プロパティに初期値を設定する場合や引数を受け取る場合は、明示的にコンストラクタを定義する必要があります。

コンストラクタはクラスの初期化を行い、クラスのインスタンスを正しく使うために不可欠な要素です。

メソッドとプロパティの定義方法

TypeScriptでは、クラスの中にプロパティとメソッドを定義することで、オブジェクトにデータと動作を持たせることができます。ここでは、クラス内でのプロパティとメソッドの定義方法について具体的なコード例を使って説明します。

プロパティの定義

プロパティはクラスが持つデータであり、クラスのインスタンスごとに異なる値を持ちます。以下は、クラス内でプロパティを定義する例です。

class Car {
    brand: string;
    model: string;
    year: number;

    constructor(brand: string, model: string, year: number) {
        this.brand = brand;
        this.model = model;
        this.year = year;
    }
}

このCarクラスでは、brandmodelyearという3つのプロパティが定義されています。コンストラクタ内で、これらのプロパティはクラスインスタンスが生成される際に初期化されます。

メソッドの定義

メソッドは、クラスのインスタンスが持つ動作や機能を定義します。次の例では、Carクラスにメソッドを追加しています。

class Car {
    brand: string;
    model: string;
    year: number;

    constructor(brand: string, model: string, year: number) {
        this.brand = brand;
        this.model = model;
        this.year = year;
    }

    // メソッドの定義
    getCarInfo(): string {
        return `${this.year} ${this.brand} ${this.model}`;
    }

    startEngine(): void {
        console.log(`${this.brand} ${this.model} is starting...`);
    }
}

この例では、getCarInfoというメソッドが定義されており、brandmodelyearプロパティの情報を文字列として返します。また、startEngineというメソッドは、エンジンを始動するメッセージをコンソールに表示するだけの動作を定義しています。

メソッドの呼び出し

インスタンスを作成し、そのメソッドを呼び出す方法を示します。

const myCar = new Car('Toyota', 'Corolla', 2020);
console.log(myCar.getCarInfo()); // "2020 Toyota Corolla"
myCar.startEngine(); // "Toyota Corolla is starting..."

このように、プロパティはクラスのデータを保持し、メソッドはそのデータに基づいた動作を定義します。TypeScriptのクラスは、プロパティとメソッドを組み合わせることで、オブジェクトの構造と振る舞いをカプセル化します。

アクセス修飾子(public, private, protected)

TypeScriptでは、クラスのプロパティやメソッドに対してアクセス修飾子を使用することで、外部からのアクセス範囲を制限したり、保護したりすることができます。アクセス修飾子は、publicprivateprotectedの3種類があり、それぞれがプロパティやメソッドに対するアクセス権を制御します。

public(パブリック)

public修飾子は、クラス内外を問わず、どこからでもアクセスできるプロパティやメソッドを定義します。デフォルトで、すべてのプロパティやメソッドはpublicとして扱われます。

class Animal {
    public name: string;

    constructor(name: string) {
        this.name = name;
    }

    public makeSound(): void {
        console.log(`${this.name} makes a sound.`);
    }
}

const cat = new Animal('Cat');
console.log(cat.name); // "Cat"
cat.makeSound(); // "Cat makes a sound."

この例では、nameプロパティとmakeSoundメソッドはpublicで定義されているため、クラスの外部から自由にアクセスできます。

private(プライベート)

private修飾子を使用すると、そのプロパティやメソッドはクラス内からのみアクセスでき、クラス外部からはアクセスできません。これにより、データを保護し、外部からの不正なアクセスを防ぐことができます。

class Animal {
    private species: string;

    constructor(species: string) {
        this.species = species;
    }

    private identify(): void {
        console.log(`This is a ${this.species}.`);
    }

    public revealSpecies(): void {
        this.identify();
    }
}

const dog = new Animal('Dog');
// console.log(dog.species); // エラー: 'species'はプライベートプロパティ
dog.revealSpecies(); // "This is a Dog."

speciesプロパティとidentifyメソッドはprivateとして定義されているため、クラスの外部から直接アクセスできません。代わりに、publicメソッドrevealSpeciesを通じて間接的にアクセスしています。

protected(プロテクテッド)

protected修飾子は、クラス内およびそのサブクラス(継承されたクラス)からのみアクセス可能なプロパティやメソッドを定義します。クラスの外部からはアクセスできませんが、継承されたクラス内では利用できます。

class Animal {
    protected type: string;

    constructor(type: string) {
        this.type = type;
    }
}

class Dog extends Animal {
    constructor() {
        super('Dog');
    }

    public getType(): void {
        console.log(`This is a ${this.type}.`);
    }
}

const dog = new Dog();
dog.getType(); // "This is a Dog."
// console.log(dog.type); // エラー: 'type'はprotectedプロパティ

typeプロパティはprotectedとして定義されているため、Dogクラス内ではアクセスできますが、クラスの外部からはアクセスできません。

アクセス修飾子の使い分け

  • public: クラス外部からもアクセス可能。汎用的なメソッドやプロパティに使用。
  • private: クラス外部からのアクセスを防ぎ、データを保護。外部に公開したくないメソッドやプロパティに使用。
  • protected: 継承されたクラス内ではアクセス可能だが、クラス外部からはアクセスできない。クラスの拡張時に使用。

アクセス修飾子を使うことで、クラスのデータを適切に管理し、セキュリティや保守性を向上させることができます。

クラスの継承

TypeScriptでは、クラスの継承を使って既存のクラスを拡張し、新しいクラスを作成することができます。継承により、コードの再利用性が高まり、共通の機能を持つクラス間でロジックを共有することが容易になります。親クラスのプロパティやメソッドを子クラスが引き継ぐことで、新たな機能を追加したり、既存の動作をオーバーライドしたりできます。

継承の基本

extendsキーワードを使用してクラスを継承します。子クラスは親クラスのすべてのプロパティとメソッドを引き継ぎます。以下は、Animalクラスを継承してDogクラスを定義する例です。

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} makes a sound.`);
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name); // 親クラスのコンストラクタを呼び出す
    }

    bark(): void {
        console.log(`${this.name} barks.`);
    }
}

const dog = new Dog('Rex');
dog.makeSound(); // "Rex makes a sound."
dog.bark();      // "Rex barks."

この例では、DogクラスはAnimalクラスを継承しています。DogクラスはAnimalクラスのnameプロパティとmakeSoundメソッドをそのまま使用し、さらにbarkという独自のメソッドを追加しています。

superキーワードの使用

子クラスで親クラスのコンストラクタを呼び出す場合、superキーワードを使います。これは、親クラスのコンストラクタ内で初期化されるプロパティを引き継ぐために必要です。

class Cat extends Animal {
    constructor(name: string) {
        super(name); // 親クラスのnameプロパティを初期化
    }

    meow(): void {
        console.log(`${this.name} meows.`);
    }
}

const cat = new Cat('Whiskers');
cat.makeSound(); // "Whiskers makes a sound."
cat.meow();      // "Whiskers meows."

superは親クラスのコンストラクタだけでなく、親クラスのメソッドを呼び出す際にも使用できます。これにより、親クラスの動作を子クラスで再利用したり、部分的に上書きしたりできます。

メソッドのオーバーライド

継承において、子クラスは親クラスのメソッドを独自の実装で上書き(オーバーライド)できます。以下の例では、DogクラスがAnimalクラスのmakeSoundメソッドをオーバーライドしています。

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }

    // 親クラスのmakeSoundをオーバーライド
    makeSound(): void {
        console.log(`${this.name} barks loudly.`);
    }
}

const dog = new Dog('Max');
dog.makeSound(); // "Max barks loudly."

オーバーライドを利用することで、親クラスの基本的な動作を保持しつつ、子クラスに特化した振る舞いを追加することができます。

継承のメリット

  1. コードの再利用: 共通の機能を親クラスに集約し、子クラスで再利用することでコードの重複を減らせます。
  2. 拡張性: 新しいクラスを作成する際、既存のクラスを拡張して新しい機能を追加できるため、開発の柔軟性が向上します。
  3. 保守性: 親クラスのロジックを変更することで、すべての子クラスに影響を与えるため、一元的な管理が可能です。

TypeScriptのクラス継承を活用することで、複雑なアプリケーションでも効率的に開発を進めることができ、共通機能の管理が容易になります。

抽象クラスとインターフェースの使い分け

TypeScriptでは、クラス設計の際に抽象クラスとインターフェースという2つの異なる手法が提供されています。これらはどちらもオブジェクトの構造を定義するために使われますが、それぞれに異なる役割と適用場面があります。ここでは、抽象クラスとインターフェースの違い、そしてそれぞれの使いどころについて詳しく説明します。

抽象クラスとは

抽象クラスは、具体的な実装を持つメソッドと、子クラスで実装を強制する抽象メソッドを含むことができます。抽象クラス自体ではインスタンスを作成できず、継承されるために存在します。

abstract class Animal {
    abstract makeSound(): void; // 抽象メソッド

    move(): void {
        console.log("The animal moves.");
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log("Bark!");
    }
}

const dog = new Dog();
dog.makeSound(); // "Bark!"
dog.move();      // "The animal moves."

この例では、AnimalクラスはmakeSoundという抽象メソッドを持ち、子クラスがその実装を提供することを強制しています。抽象クラスは共通の機能(moveメソッド)も持っているため、これを共有したい場合に使います。

インターフェースとは

インターフェースは、クラスがどのようなプロパティやメソッドを持つべきかを定義する契約(仕様書)のようなものです。インターフェース自体には実装がなく、複数のクラスが同じインターフェースを実装できます。

interface Animal {
    makeSound(): void;
}

class Cat implements Animal {
    makeSound(): void {
        console.log("Meow!");
    }
}

class Bird implements Animal {
    makeSound(): void {
        console.log("Tweet!");
    }
}

const cat = new Cat();
cat.makeSound(); // "Meow!"

const bird = new Bird();
bird.makeSound(); // "Tweet!"

インターフェースを使うと、クラスに特定の形を強制できますが、継承とは異なり、複数のインターフェースを実装できる点が特徴です。また、インターフェースは実装を持たないため、クラスが自由に実装方法を決めることができます。

抽象クラスとインターフェースの違い

  • 実装の有無: 抽象クラスは具体的なメソッドの実装を持つことができるが、インターフェースは実装を持たない。
  • 多重継承の有無: クラスは1つの抽象クラスしか継承できませんが、複数のインターフェースを実装することができます。
  • インスタンス化: 抽象クラスは直接インスタンス化できませんが、具体的なメソッドやプロパティを持つため、継承するクラスの基礎を提供します。一方、インターフェースは実装を強制するだけで、直接インスタンス化する概念はありません。

使い分けのポイント

  • 抽象クラスを使う場合: クラスに共通の実装を提供しつつ、子クラスに特定のメソッドの実装を強制したい場合。例えば、動作の一部は決まっていて、部分的に変更を加える必要があるケースに適しています。
  • インターフェースを使う場合: クラス間で構造の共通性を確保しつつ、実装の詳細は完全にクラス側に委ねたい場合。例えば、複数のクラスに共通する契約(形)を決める必要がある場合に効果的です。

両者を組み合わせた利用

実際の開発では、抽象クラスとインターフェースを組み合わせて使うことがよくあります。抽象クラスで共通のロジックを定義し、インターフェースで複数クラスに同じ契約を強制することで、より柔軟で拡張性の高いコード設計が可能になります。

interface Flyable {
    fly(): void;
}

abstract class Animal {
    abstract makeSound(): void;

    move(): void {
        console.log("The animal moves.");
    }
}

class Bird extends Animal implements Flyable {
    makeSound(): void {
        console.log("Tweet!");
    }

    fly(): void {
        console.log("The bird flies.");
    }
}

この例では、BirdクラスがAnimalクラスを継承しつつ、Flyableインターフェースを実装しています。クラス間で共通の振る舞いを持ちつつ、インターフェースを利用して特定の機能を強制することが可能です。

抽象クラスとインターフェースは、それぞれの用途に応じて適切に使い分けることで、より強力で柔軟な設計を実現できます。

静的メンバーとインスタンスメンバーの違い

TypeScriptのクラスでは、メンバー(プロパティやメソッド)を「静的メンバー」と「インスタンスメンバー」に分けて定義することができます。この違いを理解することで、クラスの設計における役割分担をより明確にし、効果的なコードを書くことができます。

インスタンスメンバーとは

インスタンスメンバーは、クラスのインスタンスごとに存在するプロパティやメソッドのことを指します。これらは、クラスのオブジェクトが作成されるたびに独自の値を持ち、インスタンスに紐づいています。

class Car {
    model: string;

    constructor(model: string) {
        this.model = model;
    }

    drive(): void {
        console.log(`${this.model} is driving.`);
    }
}

const car1 = new Car('Toyota');
const car2 = new Car('Honda');

car1.drive(); // "Toyota is driving."
car2.drive(); // "Honda is driving."

この例では、modelプロパティとdriveメソッドはインスタンスメンバーです。car1car2という2つのインスタンスはそれぞれ異なるmodel値を持ち、異なる動作をします。

静的メンバーとは

静的メンバーはクラス自体に属し、インスタンスではなくクラス全体に対して存在するプロパティやメソッドを指します。staticキーワードを使って定義され、クラスのインスタンスを作成しなくても直接アクセスできます。

class Car {
    static totalCars: number = 0;

    model: string;

    constructor(model: string) {
        this.model = model;
        Car.totalCars++; // 静的メンバーにアクセス
    }

    static getTotalCars(): number {
        return Car.totalCars; // 静的メソッド
    }

    drive(): void {
        console.log(`${this.model} is driving.`);
    }
}

const car1 = new Car('Toyota');
const car2 = new Car('Honda');

console.log(Car.getTotalCars()); // 2

この例では、totalCarsプロパティとgetTotalCarsメソッドが静的メンバーとして定義されています。totalCarsはすべてのインスタンスで共有され、クラス自体に紐づいているため、インスタンスを作成せずにCar.getTotalCars()のように直接アクセスできます。

静的メンバーとインスタンスメンバーの違い

  • インスタンスメンバー: クラスのインスタンスに関連し、インスタンスごとに異なる状態や動作を持ちます。インスタンスが生成されるたびに初期化されます。
  • 静的メンバー: クラス自体に関連し、すべてのインスタンス間で共有されます。インスタンスを生成せずにアクセスでき、クラス全体に影響を与える情報や動作を持つのに適しています。

利用例

  • インスタンスメンバー: 個々のオブジェクトが独自の状態を持つ必要がある場合(例: 各車のモデルや走行メソッド)。
  • 静的メンバー: すべてのインスタンスで共有される情報や動作を管理する場合(例: 全体のインスタンス数やグローバル設定)。

静的メンバーとインスタンスメンバーを適切に使い分けることで、効率的なクラス設計が可能になります。

クラスの応用例: オブジェクト指向プログラミングの実践

TypeScriptのクラスを活用することで、オブジェクト指向プログラミング(OOP)の基本原則である「カプセル化」「継承」「ポリモーフィズム」を実現できます。ここでは、クラスを使った具体的な応用例を通じて、OOPの考え方を実践的に理解します。

カプセル化の例

カプセル化とは、データ(プロパティ)を直接外部から操作されないようにし、データへのアクセスをメソッドを通じて行う仕組みです。これにより、データの保護と制御が可能になります。

class BankAccount {
    private balance: number;

    constructor(initialBalance: number) {
        this.balance = initialBalance;
    }

    public deposit(amount: number): void {
        if (amount > 0) {
            this.balance += amount;
        }
    }

    public withdraw(amount: number): void {
        if (amount > 0 && amount <= this.balance) {
            this.balance -= amount;
        }
    }

    public getBalance(): number {
        return this.balance;
    }
}

const myAccount = new BankAccount(1000);
myAccount.deposit(500);
myAccount.withdraw(200);
console.log(myAccount.getBalance()); // 1300

この例では、balanceプロパティはprivateとして定義され、外部から直接変更できません。代わりに、depositwithdrawメソッドを通じて間接的に操作します。これにより、適切な範囲でのみデータの変更が可能になります。

継承の応用例

クラスの継承を使うことで、既存のクラスを拡張し、コードの再利用性を高められます。次の例では、Employeeクラスを継承して、Managerクラスを作成しています。

class Employee {
    name: string;
    position: string;

    constructor(name: string, position: string) {
        this.name = name;
        this.position = position;
    }

    public work(): void {
        console.log(`${this.name} is working as a ${this.position}.`);
    }
}

class Manager extends Employee {
    constructor(name: string) {
        super(name, "Manager");
    }

    public holdMeeting(): void {
        console.log(`${this.name} is holding a meeting.`);
    }
}

const manager = new Manager("Alice");
manager.work(); // "Alice is working as a Manager."
manager.holdMeeting(); // "Alice is holding a meeting."

ここでは、ManagerクラスがEmployeeクラスを継承しています。ManagerクラスはEmployeeのすべてのプロパティとメソッドを引き継ぎつつ、独自のholdMeetingメソッドを追加しています。これにより、共通の機能を使い回しつつ、役職に応じた振る舞いを追加できます。

ポリモーフィズムの例

ポリモーフィズム(多態性)は、異なるクラスのオブジェクトが同じメソッドを共有しつつ、異なる動作をすることを意味します。以下はその応用例です。

class Animal {
    public makeSound(): void {
        console.log("Some generic animal sound");
    }
}

class Dog extends Animal {
    public makeSound(): void {
        console.log("Bark!");
    }
}

class Cat extends Animal {
    public makeSound(): void {
        console.log("Meow!");
    }
}

const animals: Animal[] = [new Dog(), new Cat(), new Animal()];

animals.forEach((animal) => {
    animal.makeSound();
});

この例では、Animalクラスが基本的なmakeSoundメソッドを持ち、DogCatクラスがそれをオーバーライドしています。animals配列には異なる種類の動物が含まれていますが、それぞれのmakeSoundメソッドは異なる動作をします。ポリモーフィズムにより、異なるオブジェクトを統一的に扱いつつ、具体的な動作を柔軟に変更できます。

オブジェクト指向プログラミングの利点

  • カプセル化: データを安全に管理し、外部からの不正アクセスを防止できます。
  • 継承: コードの重複を避け、共通機能をまとめて管理できます。
  • ポリモーフィズム: 複数のクラスで同じインターフェースや基底クラスを共有し、柔軟なコードが書けます。

これらのOOPの原則をTypeScriptのクラスで活用することで、コードのメンテナンス性が向上し、拡張しやすい設計を実現できます。

演習問題: TypeScriptでクラスを使って実装する練習

TypeScriptのクラスに関する知識を深めるために、実際にクラスを使って小さなアプリケーションを実装してみましょう。以下の演習問題では、クラス、コンストラクタ、メソッド、アクセス修飾子、継承など、これまで学んだ概念を使って問題を解決します。

問題1: ユーザー管理システムの実装

簡単なユーザー管理システムをクラスを使って作成します。以下の仕様に従って、クラスを定義してください。

  • Userクラスを作成し、usernamepasswordプロパティを持たせる。
  • Userクラスには、loginメソッドを持たせ、正しいパスワードを入力した場合にログイン成功と表示する。
  • AdminUserクラスをUserクラスから継承し、manageUsersメソッドを追加する。
  • AdminUserクラスでは、loginメソッドをオーバーライドして、管理者としてログインするメッセージを表示する。
class User {
    protected username: string;
    protected password: string;

    constructor(username: string, password: string) {
        this.username = username;
        this.password = password;
    }

    public login(inputPassword: string): void {
        if (inputPassword === this.password) {
            console.log(`${this.username} has logged in successfully.`);
        } else {
            console.log('Login failed. Incorrect password.');
        }
    }
}

class AdminUser extends User {
    constructor(username: string, password: string) {
        super(username, password);
    }

    public manageUsers(): void {
        console.log(`${this.username} is managing users.`);
    }

    public login(inputPassword: string): void {
        if (inputPassword === this.password) {
            console.log(`Admin ${this.username} has logged in successfully.`);
        } else {
            console.log('Admin login failed. Incorrect password.');
        }
    }
}

// インスタンス生成とテスト
const user1 = new User('john', 'password123');
user1.login('password123'); // "john has logged in successfully."

const admin1 = new AdminUser('admin', 'adminpass');
admin1.login('adminpass'); // "Admin admin has logged in successfully."
admin1.manageUsers(); // "admin is managing users."

問題2: ショッピングカートのクラス設計

次に、ショッピングカートをシミュレートするクラスを設計します。

  • Productクラスを作成し、namepriceプロパティを持たせる。
  • ShoppingCartクラスを作成し、複数のProductを追加できるaddProductメソッドと、カート内の合計金額を計算するcalculateTotalメソッドを定義する。
  • 追加で、商品のリストを表示するshowCartメソッドも実装してください。
class Product {
    name: string;
    price: number;

    constructor(name: string, price: number) {
        this.name = name;
        this.price = price;
    }
}

class ShoppingCart {
    private products: Product[] = [];

    public addProduct(product: Product): void {
        this.products.push(product);
        console.log(`${product.name} has been added to the cart.`);
    }

    public calculateTotal(): number {
        return this.products.reduce((total, product) => total + product.price, 0);
    }

    public showCart(): void {
        console.log("Products in your cart:");
        this.products.forEach((product) => {
            console.log(`${product.name}: $${product.price}`);
        });
        console.log(`Total: $${this.calculateTotal()}`);
    }
}

// インスタンス生成とテスト
const cart = new ShoppingCart();
const product1 = new Product('Laptop', 1000);
const product2 = new Product('Mouse', 25);

cart.addProduct(product1);
cart.addProduct(product2);

cart.showCart();
// 出力:
// Laptop has been added to the cart.
// Mouse has been added to the cart.
// Products in your cart:
// Laptop: $1000
// Mouse: $25
// Total: $1025

問題のポイント

  • 問題1では、クラスの継承とメソッドのオーバーライドを実践できます。Userクラスのloginメソッドをオーバーライドすることで、AdminUserクラスに特化した動作を実装できます。
  • 問題2では、カプセル化とメソッドを使って複数のProductオブジェクトを管理し、ショッピングカートの合計金額を計算するロジックを実装します。

演習問題に取り組むことで、クラスの基本から応用までの実践的なスキルが身に付きます。

まとめ

本記事では、TypeScriptにおけるクラスの基本的な使い方から、継承、抽象クラス、インターフェース、静的メンバーとインスタンスメンバーの違い、そしてオブジェクト指向プログラミング(OOP)の実践までを幅広く解説しました。クラスを効果的に活用することで、コードの再利用性、保守性が向上し、複雑なアプリケーションの構築が容易になります。

演習問題を通じて、クラスの基本的な設計や応用例に取り組むことで、TypeScriptのオブジェクト指向プログラミングの理解がさらに深まるでしょう。クラス設計を工夫し、効率的で拡張性の高いコードを書けるようにぜひ活用してください。

コメント

コメントする

目次