プログラミング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のオーバーライドは不要となる★ }
インターフェース
// 以下の記述は、インターフェースでは代替できない type A = number type B = A | string
- インターフェースを拡張する場合に、拡張元のインターフェースが拡張先のインターフェースに割り当て可能か検査する
- 同じスコープ内の同じ名前のインターフェースはマージされるが、同じスコープ内の同じ型エイリアスはコンパイル時エラーになる(=宣言のマージ)
- ただし、同じ名前の2つのインターフェースにそれぞれ同じ名前だが異なる型で定義されたものが存在すると、コンパイルエラーになる
クラスは構造的に型付けされる
- TypeScriptはクラスを名前ではなく構造であるメンバ関数やプロパティによって比較される
クラスにおける値と型の名前空間の違い
- TypeScriptは型と値(変数)でそれぞれ別な名前空間を持つため、
let a = 10
とtype a = number
は同じスコープにおいても、文脈から推論して別なものとして扱われる- ちなみに、JavaScriptへコンパイルすると、そもそも型エイリアスといった文法がないため、
var a = 10
だけが残る
- ちなみに、JavaScriptへコンパイルすると、そもそも型エイリアスといった文法がないため、
- クラスと列挙型は、型と値それぞれの名前空間に型と値を生成する
その他
- クラスにおけるジェネリック型の宣言は、クラススコープで宣言し、それはクラススコープ内でどこでも利用可能
- ミックスインは、相応の機能は提供していないが、独自実装可能
- finalは提供されていないため、プライベートコンストラクターを利用して実装する
書籍ではTypeScriptにおけるデザインパターンの実装も書かれており、こちらもとても参考になるので、ぜひ本を買って読んでいただきたいです。