TypeScriptでAbstract修飾子についてまとめる

study フロントエンド

Abstract修飾子

Abstractとは「抽象的な」という意味。
Abstract修飾子はアクセス修飾子とは違い、メンバ変数、メンバ関数以外にも、クラスそのものにつけることができる。

Abstract修飾子をクラスにつけた場合、そのクラスを抽象クラスと呼ぶ。メンバにつけた場合も抽象メンバと呼ばれる。

抽象クラスは以下の特徴がある。

  • 抽象クラスは直接インスタンス化することができない。抽象クラスを継承したクラス(子クラス)を作る必要がある。
  • 抽象メンバは直接アクセスできない。子クラスで具体的な処理を実装する必要がある。

試してみましょう。

type Temperture = 'hot' | 'cold';

abstract class Drink {
    name: string = 'hoge';
    private capacityMl: number = 500;
    protected price: number = 600;
    static num: number = 0;
    constructor(public temperature: Temperture) {
        Drink.num++;
        // console.log('Drink:', this.name);
        // console.log('Drink:', this.capacityMl);
        // console.log('Drink:', this.price);
    }

    abstract getTaxIncludedPrice(): number;
}

class Tea extends Drink {
    constructor(public temperature: Temperture, public brand: string) {
        super(temperature);
        // console.log('Tea:', this.name);
        // console.log('Tea:', this.capacityMl); // プロパティ 'capacityMl' はプライベートで、クラス 'Drink' 内でのみアクセスできます。ts(2341)
        // console.log('Tea:', this.price);
    }

    getTaxIncludedPrice(): number {
        return this.price * 1.1;
    }
}

const drink1 = new Drink('hot'); //抽象クラスのインスタンスは作成できません。ts(2511)
const tea1 = new Tea('hot', 'assam');
console.log('tea1:', tea1.getTaxIncludedPrice()); // tea1: 660

前回作った飲み物クラスにabstractをつけて抽象クラスにしました。
そうすると、飲み物クラスはインスタンスが作成できなくなりました。

また、飲み物クラスに税込価格を返す抽象メンバ関数を作成しました。
そうすると、紅茶クラスで

非抽象クラス 'Tea' はクラス 'Drink' からの継承抽象メンバー 'getTaxIncludedPrice' を実装しません。ts(2515)

とエラーが出るようになりました。

子クラスである紅茶クラスで具体的な実装を書く必要があります。

紅茶クラスでgetTaxIncludedPriceを実装すると、飲み物クラスで定義していたpriceの600が660と計算されて返却されました。

使い道

抽象クラスは子クラスのドキュメントとなるような存在です。
予め定義を決めておくことで挙動や変数を統一し、処理の流れをわかりやすく、また可読性をあげることができます。

参考

30歳からのプログラミング TypeScript で抽象クラスと抽象メンバを使って変更に強いコードを設計する

コメント

タイトルとURLをコピーしました