本セッションの登壇者
セッション動画(YouTubeチャンネル登録もお願いします。)
こんにちは、uhyoです。
私の担当はTypeScriptの上級テクニックということで、「TypeScript4.7と型レベルプログラミング」についてお話ししようと思います。
まず最初に私の自己紹介です。今、LINEという会社でフロントエンドエンジニアをやっておりまして、専門はTypeScriptとReactなんですが、TechFeedさんではTypeScriptのエキスパートとしてやらせていただいております。
ここでちょっと宣伝が入るんですけども、4月にTypeScriptの入門書『プロを目指す人のためのTypeScript入門』(技術評論社)という本を発売しました。我ながら良い本だと思いますし、とくにこのセッションを見ているような皆さんは、わりとTypeScriptに強い方が多いとは思うんですが、教科書的な感じの使い方もできるようにしていますので、そういった使い方もおすすめです。
型レベルプログラミングとは
さて、TypeScriptの上級テクニックと言ったら私はやっぱり型レベルプログラミングじゃないかなと思います。
型レベルプログラミングって何?というと、私の見解ですが「型でより正確なロジックを記述して、それによってコードの安全性を高める」、そういった目的のために既存の型から新たな型を創出する手法、これが型レベルプログラミングじゃないかなと思っています。
そもそもTypeScriptで型を書くのは安全性を高めるためにやっていることなんですよね。TypeScriptに型を書いて「俺はこういう気持ちなんだから汲んでよね」ってTypeScriptコンパイラさんに教えて、TypeScriptコンパイラさんがその型をチェックしてくれるわけです。そこでなんか言ってることと実際に書いてあるコードが違ったりしたら「お前違うぞ」って言って怒ってくれる…というのがTypeScriptの安全性なんですね。
なのでTypeScriptコンパイラさんに意図をより正確に伝えるということ、要するにこれが型で、より安全なロジックを記述するということなんです。これをより高度に行って、より安全性を得るために型レベルプログラミングをやるんだと思います。
ここは詳細には説明しませんけど、TypeScriptの機能のうち、ここに書いてあるようなものは型レベルプログラミングに結構使われます。keyof / typeof / mapped types / conditional types / union distribution / template literal typesですね。このconditional typesというのがとくに良くて、型で条件分岐を行ってくれるのですが、構文の都合上、世にも珍しい四項演算子になっています。
これが私が最近業務で書いた実例です。多分読めない方が多いと思うんですけど、まあ大丈夫です。
これ何をやってるか簡単に説明だけをしておくと、GraphQLのサーバーを書くときにリゾルバっていうのをたくさん書かなきゃいけないんですけど、その一覧というのはコード生成してくれるんですね。
でもその中で書かなきゃいけないやつと書かなくても別にいいやつがありまして、そいつらをちゃんとより分けて書かなきゃいけないものだけを抽出した型というのがこれになります。興味のある方は後でじっくり見てください。
TypeScript 4.7の3つの新機能
で、TypeScript4.7、これ、つい何日か前にRCが発表されまして、今月TypeScript4.7の正式バージョンがリリースされる予定です(注: 5月24日にリリース済み。
いろんな新機能がありまして、たとえばNode.js向けESM対応とかはけっこう反響を呼んでいるんですけども、その中でもここに紹介している3つの機能、これらは型プログラミングにも役立つと思うので、この場を借りて紹介しようと思います。
1つ目、extends Constraints on infer Type Variables です。
いま画面に出ているコードの黄色の下線を引いてるところ、こういう文法が新しく追加されましたのでこれを書けるようになります。
要するにこれですね。世にも珍しい四項演算子をこれまで2回ネストしなきゃいけなかったっていうのが読みにくかったんですけども、それを一発で書けるようになるという、そういういい感じの文法になっています。
次はこれですね、Instantiation Expressionsです。
ここに書いてあるコードは何かというと、funcっていう関数が1つの型引数を持っているジェネリクス関数で、それに応じて返り値の型が変わるような関数なんです。ここで定義されているtype FuncRetForNumberとは、このfuncという関数にnumber型の型引数を与えたときの返り値は何かを計算する型です。
funcに型注釈を明示的に書いていないんですけど、typeofというやつを使うことによって型推論の結果を得ることができるんです。
従来は1回これをやるために、わざとランタイムに(使わないんだけど)関数_fを定義して、それを経由してReturnTypeというヘルパを使うことによって返り値の型を無事に得ていたんです。けれども、Instantiation ExpressionsというのがTypeScript4.7で追加されまして、これを使うと「funcの返り値の型は何ですか」という感じで一発でクエリすることができます。ちなみに返り値はnumberの配列型ですね。これはとても便利です。
もうひとつ、これはけっこう賑わっていたので知ってる方も多いかもしれないですが、typeの型引数にoutとかinとかそういうvariance、contravariantとかcovariantですね、あれをアノテーションできることになりました。
従来オブジェクト型に書いていないけど、ちょっとvarianceが必要というときに、ある種、幽霊型みたいな感じでユニークシンボルを型にKeyとして持たせて、そこで変数を表現するというテクニックがあったんです。けれども、TypeScript 4.7で新しくこのoutとかinという構文が追加されたことによって、そういった面倒くさいワークアラウンドをすることなしにこういった変性をアピールすることができます。これはとても嬉しいですね。
今回紹介したかったことは以上になります。皆さんもぜひ楽しく型レベルプログラミングをやって、高度な安全性を高めてみてください。
以上です。ありがとうございました。