プロを目指す人のためのTypeScript 本の感想 #ブルーベリー本
自分も教える事が多いので、読み手にどういう風に学んでほしいか、自分がどういう風に伝えるべきか、という視点で読んだ。
1章・イントロダクション
そもそもTypeScript とはなにかみたいな話。
コンパイルエラーが出ている状態ではプログラムが完成したとは言えません。
力強い
コンパイルエラーをただ避けるのではなく、利用する気持ち で TypeScript プログラミングに臨みましょう。
初心者に型違反の向き合い方を諭す話。IDEの補助になるとか。
TS年表で取り上げてるのが特徴的。exactOptionalProperty を取り上げてたり。
TSの型はランタイムに影響しない、という話を何度も解説している。これは初心者の誤解がとても多いので、必要だと思う。何度いっても、伝わって欲しい人に伝わらないのだが…
enum や namespace については意図的に解説しない。過去のTS独自路線だったときの機能なので。自分も同じポリシーだが、enum について異論がある人はいそう。
TS実行するまでのフローがやっぱり多い。この辺は deno が普及したらもっと楽になるのに…と思った
2章はプログラミング初心者に式と文という概念を伝えるのによさそう。コンパイラの概念が透けてみえるようになる。
let を避けろというコラムわかる。
BigInt の解説するんだ。
全体的にJSの言語仕様をTSという側面から解釈しつつ学ぶ、という構成になってる。この構成が初学者に伝わるかというと、完全なJS初学者には無理で他のプログラミング言語の経験は多少要求される。
3章
object への型注釈の文法解説が結構しんどく感じた。文法的に似てるがそれ故に混乱する。そういえば自分も複雑なインラインの型書いてると、今型なのかインスタンスなのか、結構間違ってる気がするので、言語自体が抱える特徴かもしれない。
type と interface の使い分け、今となっては何が何だかわからない気がした。type がない時代があってそれ以降は〜と書いてあるけど、昔の type はジェネリクスとれなくて、途中から取れるようになったので、表現的に interface を上回ったのはそれ以降。
この手の本は class から始まることが多いが、徹底して object に対する型で解説してるのが現場感があり、よい。
型スコープでの typeof、最初使い方わからなかったのを思い出した。
自分もよく redux で type State = typeof initialState をやめろと言ってた気がする。
subtyping と union は既存のJava/C#/C++みたいな言語に慣れてる人ほど柔軟さに戸惑うので、TS初体験はここを重点的に読むべきかも。
この本を読むと readonly が強力な機能に見えるが、実際にはネストした先に影響がないので、Deep な readonly は別途作らないといけないことの解説が必要かも。
本書で言及はないが、自分はタプル型は自分はビルドサイズを圧縮するのに使ってる。キーがなくなるので、特に異なる型のデータをタプルに詰めるときはほぼミスしないので便利。
配列は .at 使いたいよね… https://github.com/tc39/proposal-relative-indexing-method
デフォルト引数がnullに適用されないの納得行かないときがある。
4章
本当に class の存在を無視したまま解説が進む(好き)
関数の返り値の型を書く意味、推論に頼ってるとミスったときに早期に気づけない、というのはそう。徹頭徹尾つけろというより、ミスりそうなときに付ける、というのはバランスがいい。一部のリンターに強制されてだるいときがある。
TS は健全性より安全性を損ねてでも表現力を重視している、というのを伝えるの難しいな…になった。
部分型を共変、 反変という言葉を使わずに解説するのしんどそうに見える。と思ったら途中から出てきた。
readonly 見てると全部をデフォルト readonly にして Rust みたいな mut キーワードとか欲しくなってきた。Mut<T>使わない限り書き込めない、みたいな。
解説読みながら思ったけど、やっぱ型引数多くなった時にキーワード引数的なことがしたい…
5章
やっとクラス。
const user: User = new User
は他の言語からみると普通だけど、たしかに3章のオブジェクトベースで考えるとここに違和感が出る。とくにJS は class の扱いがファーストクラスではないので、TSにおいても特殊化といえるのはそう。
this の型は奥深い、というか正直あまり考えたくない。
コンストラクタ制約についての解説。そういえばTSのコンストラクタは非同期取れないので、非同期メンバが交じるとコンストラクタ制約が満たしづらくて、static method のファクトリパターンで private constructor を使う、という実装をすることがあるんだけど、みんなどうしてるんだろう。
クラス式はどうしても動的クラスが必要な時に関数の返り値として使うときぐらいしか使わないよなー。
#
と private のプライベート使い分けは今ちょうど移行期なので解説する時期は都合悪そう。
静的初期化ブロックは自分まだ使ったことなかった。
型の名前空間とJSのランタイムの名前空間がわかれている話、経験を積感覚的にはわかるが、初学者は特に苦労しそう。
instanceof で推論させる話は、他の Type Refinement の振る舞いとあわせて別で解説するのがいいんじゃないかとは思った。
著者へのコメントというか、一般的なTSユーザーへの気持ちだけど、個人的には class extends を使う前にアダプターパターン等で class implements を検討してほしい、というか、class を限界まで使わないでほしい。
JS の Error、やはり使いづらい気持ちになる。
class の使用に関しては、object 型ではできない開放閉鎖原則の徹底の際に使うべきだという気持ちになった。
6章 ユニオンとインターセクション
他の静的型の言語の経験がある人がTSならではの特徴を掴むには、3章と6章を重点的に読むのがよさそう。
インターセクションの絞り込みは結構理解に苦労したのを思い出した。
実際には存在できない型、自分は as の upcast と組み合わせて Opaque な型を作るのにつかうけど、下手に解説すると誤読しそうな人が出そう。 type Id = string & { _: 'id' }
みたいなやつ。
コントロールフロー解析はとくに他の静的型の言語からすると感動する部分なのでよく読んでほしい。
as の危険性。この辺から伝えるのが難しくなる。とくに型を信頼しすぎて通らないと動かないと誤解してる人が as で修正したつもりになってバグを作り込んでることがある。
! は非標準だが ?. が標準になってしまったので、!. の位置付けが説明しづらい。
any への向き合い方。人によるよね。自分が書いたライブラリが利用側で全部 any にされてるとウーンとなることがある。
自分も型述語は最初なぜコントロールフロー解析に関与できるのかわからなかったが、TS本体のコード読んで理解した。 ts.isSoureFile() とか
asserts はまだ使ったことがなく、知らなかった。
mapped types 未だにわからん、というか書き方忘れってググって書いてる。
conditional types も object と一緒で既存のキーワードを型空間で別の意味で使ってるから混乱しがち。
7章 モジュールシステム
ESMわかってれば飛ばしていいが、 import type は抑える必要がある。
export default はエディタ補完が弱いので使わない。
node 周りは module: nodenext や .mts の紹介ができればよかったんだろうけど、ややこしい機能だし、現状も賛否あるので、本に書くのは難しそう。
ambient type のパーサの気持ち未だにわからない。
8章 非同期
これは TS の非同期を学ぶというより(そんな実体はない)、TSの型定義を通してPromiseの実体と async/await の実体を理解する、という視点で読むのがいい気がする。
初学者はなんで async/await があるのに Promise なんか学ばないといけないんだ、といってるのをちらほらみるが、型の視点からみてもPromise理解しないとやはり正しい理解に至れないと思う。
この辺は型もだけど実行環境のセマンティクスが絡んでくるので説明が難しい。
9章 コンパイラオプション
どの設定が推奨か分かりづらいので、こういう章も必要か。
感想
JS自体に詳しくなりたい人は最初から読むべきだが、JSに慣れてTS特有の表現を抑えたい人は、3章 6章 8章を重点的に読むのをおすすめする。
完全初学者はスコープ外なんだろうけど、わかる部分もおそらくあり、わからない部分を飛ばして読んでもあとで戻ってくるのに便利。読める部分と読めない部分がはっきり分かれそうだが。
最近は Promise と async/await の学習が話題になることが多いが、TSの型の視点から理解するのは学習方法の一つとしていいかもしれない。
オブジェクト型リテラルとユニオンのコントロールフロー解析が他の言語と比べたときにTSが明らかに異質に発達してる部分なので、型システム詳しい人にこそ、その部分を楽しんでほしい。
振り返ると、TSの型システムの異常な柔軟さがどこで生まれたか、型アノテーションがランタイムに関与しないと徹底した上でさらに一部の健全性の担保を利用者に押し付けて、その上で他の汎用言語では難しい型レベル計算を導入するという異常な意思決定をしてるところに由来する気がする。