zooo-log

読んだものとか、学んだこととか

プログラミングTypeScriptを読んだ(5章)

前回記事(プログラミングTypeScriptを読んだ(4章) - zooo-log)からの続きです。 5章読み終わりました。

基本的にはオブジェクト指向言語と同じ考え方で、TypeScriptと他の言語とが異なりそうなポイントを確認しました。 また、型エイリアスとインターフェースの差異は、3章での型エイリアス登場時にとても気になっていた点だったので、この章で記載されていて、とても勉強になりました。

ただ、型と値の名前空間が違うというのは、個人的には意外な点でした。(ここは自分の解釈が正しいかちょっと怪しいです。。)

クラスとインターフェース

クラスと継承

  • アクセス修飾子を付与しない場合、デフォルトで public 扱いとなる
  • インスタンスプロパティを宣言するときに、readonly修飾子を付与することができる

super

React書いているとよく出てくるsuper呼び出しですが、詳しい記事があったので、合わせて読むと良いと思いました。 qiita.com

戻り値の型としてのthis

  • メンバ関数の戻り値として自身のインスタンスを返したい場合、そのサブクラスにおいて、オーバーライドする必要がある。サブクラスを作るごとに、メンバ関数の戻り値を再定義するためにオーバーライドするのは面倒なので、戻り値の型としてthisを用いることでサブクラス内でオーバーライドが不要になる
// オーバーライドが必要な書き方
class Parent {
    has(value: number): boolean{
        // 
    }
    add(value: number): Parent{
        // 
    }
}

class Child {
    delete(value: number): boolean{
        // 
    }
    add(value: number): Child{ // 自身のインスタンスを返したいので、オーバーライドが必要になる
        // 
    }
}

// thisを用いた、オーバーライドが不要になる書き方
class Parent {
    has(value: number): boolean{
        // 
    }
    add(value: number): this{
        // 
    }
}

class Child {
    delete(value: number): boolean{
        // 
    }
    // Childクラスにおいて、addのオーバーライドは不要となる★
}

インターフェース

  • インターフェースと型エイリアスはほとんど同じ機能を提供するが3つの違いがある
  • エイリアスは右辺に任意の型・型の式(合併や交差)を指定可能だが、インターフェースは指定できない
// 以下の記述は、インターフェースでは代替できない
type A = number
type B = A | string
  • インターフェースを拡張する場合に、拡張元のインターフェースが拡張先のインターフェースに割り当て可能か検査する
  • 同じスコープ内の同じ名前のインターフェースはマージされるが、同じスコープ内の同じ型エイリアスコンパイル時エラーになる(=宣言のマージ)
    • ただし、同じ名前の2つのインターフェースにそれぞれ同じ名前だが異なる型で定義されたものが存在すると、コンパイルエラーになる

クラスは構造的に型付けされる

  • TypeScriptはクラスを名前ではなく構造であるメンバ関数やプロパティによって比較される
    • 同じ名前のメンバ関数を持ったクラスであれば、別々なクラスのインスタンスであっても割り当て可能
    • 例えば、MaleクラスとFemaleクラスにgetAge(): numberという同名かつ戻り値の型が同じメンバ関数が実装されていれば、関数 isHuman(person: Male)に対してMaleクラスのインスタンスも、Femaleクラスのインスタンスも割り当てることが可能
    • 中身の実装は異なっていても、問題ないが構造はチェックしているので、戻り値と関数名が同じであることが条件

クラスにおける値と型の名前空間の違い

その他

  • クラスにおけるジェネリック型の宣言は、クラススコープで宣言し、それはクラススコープ内でどこでも利用可能
    • インスタンスメソッドに対しても個別に宣言できる(クラススコープで定義しているものと共存可能)
    • ただし、静的メソッドではクラスのジェネリックにアクセスできないので、独自に宣言する必要あり(同名のジェネリックも宣言可能)
  • ミックスインは、相応の機能は提供していないが、独自実装可能
  • finalは提供されていないため、プライベートコンストラクターを利用して実装する

書籍ではTypeScriptにおけるデザインパターンの実装も書かれており、こちらもとても参考になるので、ぜひ本を買って読んでいただきたいです。