そろそろ体系的に学ぶ必要のあるTypeScriptのメモ
ORELLYのTypeScriptを読むので、雑にメモしてく。
タイトルごとに区分するが、特に何もなければ書かない(タイトルのみ)
1章 イントロダクション
型安全性 → 型を使って、プログラムが不正なことをしないように防ぐこと
2章 TypeScript全体像
TypeScriptが独特なのは、バイトコードへと直接コンパイルする代わりに、なんと JavaScriptコードへとコンパイルする
TypeScriptコンパイラー(TSC)がよしなに抽象構文木(AST:abstract syntax tree)してくれる
大抵型推論があるので、明示的にアノテーションしなくてもOKな場合も多い。
コンパイル時にいチェックしてくれるのは神。
Jsだと実行時まで気づかない。。
3章 型について
型アノテーション(type annotation:明示的な型の指定)
anyはゴッドファーザー。
unknownは推論はしない。型を比較はできる。
もし、その特定の型としたことを想定したいのなら、typeof
等で分岐処理する必要がある
|
|
明示的 → 実際に代入
推論 → 型に予測してもらう
基本的には推論でいい。
リテラル型 → ただ1つの値を表し、それ以外の値は受け入れない型
constを使うと再代入ができないのでリテラル型になる
|
|
オブジェクトリテラル型とインデックスシグネチャについてはまた復習する
・オブジェクトリテラル({})は、オブジェクトの型を即席で定義するために用いられる。
・インデックスシグネチャ([key: T]: U)は、オブジェクトが、複数のkey(型T)を含む可能性があり値はU型になることを示している。
3.2.9 型alias
型エイリアスを使うかどうかを決めるときには、ある値に名前を付けて独立した変数にするかどうかを決めるときと同様の判断に従う
3.2.11 タプル
|
|
タプル型は不均一なリストを安全にコード化するだけでなく、それが型付けするリストの長さを限定する。これらの機能により、
従来のシンプルな配列よりもはるかに大きな安全が得られる
3.2.12 null undefined void never
undefinedは、あるものがまだ定義されていないことを意味し、nullは、値が欠如していることを意味します
型 | 意味 |
---|---|
null | 値の欠如 |
void | return文を持たない関数の戻り値 |
undefined | 値がまだ割り当てられていない変数 |
never | 決して戻ることのない関数の戻り値 |
4章 関数
4-1 関数の宣言と呼び出し
JSの関数定義方法は5つある
|
|
4.1.1 オプションパラメータとデフォルトパラメータ
オプションパラメータ → userId?
デフォルトパラメータ → userId = “not assigned in”
デフォルトパラメータを使うほうがよさげ
4.1.2 レストパラメータ
可変長引数のこと
…numbers みたいなやつ
4.1.3 call apply bind
呼び出し方のやつ。さらっとしか見てない。
あんま使うイメージない
4.1.4 thisの型付け
関数でthisを使う場合は、期待するthisの型を、最初のパラメータとして宣言すればいいっぽい
4.1.5 ジェネレーター
https://typescript-jp.gitbook.io/deep-dive/future-javascript/generators
遅延評価?
あまり使ったことなかった
4.1.6 イテレーター
イテレーターはジェネレータの裏返し。ジェネレーターが一連の値を生成するのに対し、イテレーターは
それを利用する。
|
|
わからん。。
4.1.7 呼び出しシグネチャ
|
|
4.1.8 文脈的型付
4.1.9 オーバーロードされた関数の型
後で読む
4.2 ポリモーフィズム
ジェネリクス型の話。
ここむずいんよなあぁ。
【TypeScript】Generics(ジェネリックス)を理解する
↑上記記事わかりやすい。
要するに、関数の中でおなじ型が入るなら、
4.2.3 ジェネリックの型推論
4.2.4 ジェネリック型エイリアス
4.2.5 制限付きポリモーフィズム
4.2.5.1 複数の制約を持つ制限付きポリモーフィズム
ジェネリクスの部分は後で書く。
4.3 型駆動開発
まず型シグネチャで概略を記述し、その後で値を埋め込むプログラミングのスタイル
|
|
これまでmapを見たことがなかったとしてもmapが何をするかについてある程度は直観的にわかるはずです。つまり、Tの配列と、Tから Uへとマッピングする関数を取り、Uの配列を返すということです。それを知るために、その関数の実装を見る必要はありません!
↑ 直感的にまだ分かるようにはなっていないが、型の重要さは分かる。
5章 クラスとインターフェイス
チェスを例にオブジェクト指向
publicとprivateはRubyにもあるので省略。
protected → このクラスとサブクラスのインスタンスからアクセス可能。
5.2 super
5.3 戻り値の型としてthis を使用する
5.4 インターフェイス
type
と interface
の違いは、
1.型エイリアス(type)のほうが、右辺に任意の型を指定できるという点で、より汎用的である点
|
|
上記をインターフェイス型に変換することはできない
2.インターフェースを拡張する場合に、TypeScriptは、拡張元のインターフェースが拡張先のインターフェースに割り当て可能かどうかを確認する点。
|
|
3.同じスコープ内に同じ名前のインターフェースが複数存在する場合、それらは自動的にマージされる点
→ 宣言のマージ という
5.4.1 宣言のマージ
interfaceとtypeの違い、そして何を使うべきかについて
↑ だと インターフェイス型を基本使うように公式も言っているらしい。現場によって異なるのか確認はしたほうがよさそう
5.4.2 実装
クラスを宣言するときに implementsキーワードを使うと、そのクラスが特定のインターフェースを
満たしていることを表現できる
5.4.3 「インターフェースの実装」対「抽象クラスの拡張」
5.5 クラスは構造的に型付けされる
5.6 クラスは値と型の両方を宣言する
TypeScript で表現できることの多くは、値か型の「どちらか」
5.7 ポリモーフィズム
復習する
5.8 ミックスイン
● 状態(すなわち、インスタンスプロパティ)を持つことができます。
● 具象メソッド(抽象メソッドでないもの)だけを提供できます。
● コンストラクターを持つことができます。コンストラクターは、クラスがミックスされた順序と同じ順序で呼び出されます。
|
|
↑ Userはデバッグ出来るクラスを拡張したクラスを持っているからデバッグできる。むずいなここ。。
5.9 デコレーター
デコレーターはまだ実験的なものらしい。(2022/03)
TypeScript のデコレーターがより成熟した機能になるまで、その使用は避け、代わりに通常の関数を 使用することをお勧めします。
って書いてあったのでスルー
5.10 final クラスをシュミレートする
finalとは、クラスを拡張不可と指定したり、メソッドをオーバーライド不可と指定したりするために、いくつかの言語で使われるキーワード
クラスを直接インスタンス化することも防止します。しかし、finalクラスに対して 私たちが望むのは、それを拡張できなくすることだけで、インスタンス化の機能は残しておく必要がある時につかう
5.11 デザインパターン
ファクトリー(Factory)パターンは、何らかの型のオブジェクトを作成するための方法で、どのよう
な具体的なオブジェクトを作成すべきかの決定を、そのオブジェクトを作成する特定のファクトリー(工場の意)に任せます
ビルダー(Builder)パターンは、オブジェクトの構築と、そのオブジェクトを実際に実装する方法と
を分離するためのもの
コードは省略。
6章 高度な型
6.1 型の間の関係
6.1.1 サブタイプとスーパータイプ
サブタイプとは? → BがAのサブタイプなら、BはAの要求される型を安全に使える
6.1.2 変性
パラメーター化された型(ジェネリック型)や複雑な型は、複雑になりがち
6.1.2.1 形状の配列と変性
不変性(invariance) Tそのものを必要とする。
共変性(covariance) <:Tであるものを必要とする。
反変性(contravariance) >:Tであるものを必要とする。
双変性(bivariance) <:Tまたは >:Tであれば OK。
6.1.2.2 関数の変性
Crow < Bird < Animal で、変性を説明しているがテストコードがうまく動かず。。
6.1.3 割当可能性
- A <:Bである。
- A が anyである。
であれば割当可能
6.1.4 型の拡大
ミュータブルなら拡大され
イミュータブルなら拡大されない
nullまたは undefinedに初期化された変数は、anyに拡大される
6.1.4.1 constアサーション
TypeScript には特別なconstアサーションが用意されており、これを使うと、宣言と同時に型の拡大を抑えることができます。
6.1.4.2 過剰プロパティチェック
6.1.5 型の絞り込み
6.2 完全性
|
|
上記を解決するのは Day | undefined にするか、 全部 case文で書くか
6.3 高度なオブジェクト型
ルックアップ方式。← 定義済みの型[“キー”]と書くことで、指定したキーに対応する型を取り出すことができる
6.3.1.2 keyof 演算子
|
|
上記の keyofを使うと、こんな感じにできる
|
|
oの型が {a: number, b: string, c: boolean}
である場合
keyof O は a/b/c K はnumber/string/boolean になる。
ので、型が違うとエラーになる
6.3.2 レコード型
入れ子になっているものをすっきり書くやつ
Record<K,T>
【TypeScript】「Record」型について
|
|
6.3.3 マップ型
後で復習
6.3.4 コンパニオンオブジェクトパターン
|
|
利用する側では、
|
|
unit と value を importして指定出来る感じ。便利。
6.4 関数にまつわる高度な型
|
|
タプルで、可変長引数で表すとき上記のように書く。
すげえ。でも配列で可変長引数で何でもOKにするパターンを想定してコードを書くのってどうなの?
柔軟なんだよっていうことだけ頭にいれておこう
6.4.2 ユーザー定義型ガード
|
|
6.5 条件型
|
|
型レベルの三項演算子。。最もユニークとかかれていたがイマイチぴんとこな。
6.5.1 分配条件型
型定義に条件分岐を持ち込むことができる。
T extends U ? A : B
|
|
型の条件分岐。頭の片隅にいれておこう
TypeScript の条件型(Conditional Type)と infer キーワード
6.5.2 inder キーワード
inferはその条件分岐で推論された型を指すときに用いることができます。
ジェネリック型を関数でいうところの引数(props)と呼ぶならば、
inferは引数によって動的に値が変化する変数のようなもので、infer Uと記述したら、U型を型情報に含めることができます。
6.5.3 組み込みの条件型
|
|
6.6 エスケープハッチ
省略
6.7 名前的型をシュミレートする
同じ string 様々な Idを定義していた時の引数を、Id別に関数化して代入できないようにするイメージ。
6.8 プロトタイプを安全に拡張する
省略
6.9 まとめ
すべてのものを理解できていなかったり、覚えていなかったりしても、大丈夫です。何かをより安全 に表現する方法に苦労して取り組んでいるときに、この章に戻り、リファレンスとして活用してください。
この一行でだいぶ安心する。笑