🎍

型レベルプログラミングとは?(紹介記事)

2023/01/23に公開

型レベルプログラミングの入門記事を書いたので社内で共有したところ、「型レベルプログラミングって何ですか?」という質問をいただきました。

「型とは何か」「TypeScriptの型システムがすごい」ということを伝えたのですが、「型レベルプログラミングとは?」を自分で整理しておきたいと思ったので今回の記事を書くことにしました。

型レベルプログラミングが初耳の方は、おおよそ次のことが気になるのかなと想像します。

  • 何なの?
  • 学ぶメリットは?
  • どうやって学ぶの?

私はJava, Swiftなども経験していますが、前提はTypeScriptとしてそれぞれ考えを書いていきます。

何なの?

以下のように定義を考えました。

型レベルプログラミングは、型を対象としたプログラミングです。型はさまざまなデータの構造や性質、あるいは関数やクラスを表現することが出来ます。目的の型をどうすれば作れるのかを考えてコードで表現すること、それが型レベルプログラミングです。

Wikiのようなところで型レベルプログラミングが説明されているわけではありません。しかしGoogleで調べると記事がいくつもヒットします。HaskellやTypeScriptにおける文脈で登場するようです。また型レベルプログラミングよりも先に「型パズル」という言葉があり、この2つは同義だと思っています。どちらを使ってもかまわないと思いますが、私の観測範囲でたまたま「型レベルプログラミング」という言葉が印象に残ってそのまま使い始めた、という感じです。

調べてみると型レベルプログラミングや型パズルを定義している記事は少なかったですが、TS界隈では有名人のuhyoさんはこちらのスライドで型レベルプログラミングを次のように定義しています。

型でより正確なロジックを記述し、
コードの安全性を高めるために
既存の型から新たな型を創出する手法の総称

なるほど。

そもそも型って?

ここまで型とは何か説明せずに進めてきました。この記事を読まれている時点で何らかの理解を持つ人が多いとは思いますが、私が「なるほど」と思えた記事を2つ紹介させてください。

わかりやすい、型(Type)の説明より。

型(Type)とは集合(Set)のことです。

この説明はとても明快だと思います。

静的型が、コードの品質を高める方法として本当に優れたものだと言えるのでしょうか?...

静的型とは、異なるデータ型が流れるパイプでは、ジョイントの断面の形が異なるようにしておくことで、パイプがそもそも繋がらないようにしておく仕組みです。

こちらも実用的な視点で型について説明していると思います。

学ぶメリットは?

私の定義だと静的型付け言語を使ってプログラミングしていれば、同時に型レベルプログラミングしていると言えます。しかし開発で「型レベルプログラミング」を意識する機会があるとすれば次のような機会かと思います。

  • コードで扱うデータの型をきれいに定義したいとき
  • 型レベルでライブラリーを使いやすくしたいとき

型を扱うための基本的な理解だけでも開発は可能です。可能ですが、型による制限を自在にコントロールできるとより安全に、自然に、補完などを活用して効率的に、コードを書くことが可能になります。

またライブラリーを開発する上では、より高度な推論が働くように型レベルプログラミングされていると、とても使い心地がよいものになります。例えばスキーマバリデーションライブラリーzodinferは、スキーマの定義から簡単に型が取り出せるようにライブラリー側が工夫してくれているので、zodスキーマと型定義の2重管理が避けられます。洗練された方法で型が扱えるライブラリーがいくつも成長してきていて、TypeScriptによる開発がどんどん楽しくなっていると思います。

"型パズル"の付き合い方というスライドでは「なぜ型をパズルするのか?」という問いについて、次のように語られていました。

日々かかる思考コストを削減したい
コードの意図の通りに推論させたい
型で落ちたらバグっている、型が通ればバグってないにしたい
型推論のためだけに書くコードを減らしたい
補完が効く しあわせになりたい

どれもその通りだと思います。「補完が効く しあわせになりたい」というのはとても共感できます。型について真剣に考えられているライブラリーを使っているとすごく気持ちいいです。しあわせです。

どうやって学ぶの?

学ぶための教材と使い方を紹介します。

サバイバルTypeScript

このドキュメントは私もよくお世話になります。こちらのいいところはコミット履歴を見ると活発なライブラリーのように頻繁にアップデートされているところです。

サバイバルTypeScript(GitHub)

ボリュームがすごいので「このサイトをすべて読もう」と意気込んだことはありませんが、「TypeScriptのあらまし」は目を通しておくとモチベーションになります。おそらくTypeScript初心者が一人前になるところまではサバイバルTypeScriptの最適な教材だと思います。もちろん個人の見解です。

型レベルプログラミングの準備として次の内容は理解しておくとよいでしょう。

これも個人の見解ですが、型の再利用のMapped typesあたりが型レベルプログラミングの入り口だと思っています。判別可能なユニオン型が使いこなせるようになっていると実務でもかなり安全なコード、自然なコードが書けるようになるのでおすすめです。

TypeScript型レベルプログラミングの細かいテクニック

タイトルの通りです。一通り読んでおけば困った時に参考になります。また、再帰呼び出し回数の上限突破といった高度でマニアックなネタについても取り扱っています。サバイバルTypeScriptと同じ筆者の記事です。

型レベルプログラミング入門

タイトルの通り、型レベルプログラミングの入門記事です。
型レベルプログラミングでは条件分岐をConditional typesで、ループは再帰で書きます。型レベルプログラミング特有の書き方に慣れてもらうため、考え方をかなり噛み砕いて説明しています。再帰で考えることに慣れていない人には是非読んでもらいたい内容です。

type-challenges

TypeScriptの型システムについて、サバイバルTypeScript型レベルプログラミング入門で理解したら、こちらのサイトで腕試ししましょう。難易度別にたくさんの型レベルプログラミングの問題が紹介されています。一通り歩いてみると新しいテクニックの発見や、きちんと理解していない型の振る舞いについて解説されていて勉強になることがあります。

型レベルプログラミングでN×Nの数独を解く

数独を解くためのアプローチから、型を細分化し、最終的に数独を解く型を完成させるところまでを解説しています。

Object.create(null)

このサイトは最新・最先端の型レベルプログラミングのテクニックを紹介しています。(私が勝手にそう思っています。)

私がTypeScriptに入門したのは2018年でした。当時はReact×TypeScriptでフロントを構築するプロジェクトに参画していましたが、型エラーが発生しては解決する方法を調べて学んでいました。その時に出会ったのがこちらのサイトです。

以下の記事は私のスキルが低すぎて当時は理解できなかったのですが、記事で実現されていることに興奮してどうにか理解してやろうと繰り返し読んだ記憶があります。まだ型パズル、型レベルプログラミングといった概念を知らずに、型ですごいことをやっている人がいる、型の最先端の情報に触れている、という印象でした。

改めて読み返してみると、型を扱うコードが読めるようになっていること、お題に対して手を動かすイメージが湧くことなど自分の成長を感じます。またTypeScriptの進化によって今ならinfer ... extends ...のような自然な書き方ができることなど、いろいろ感慨深いです。

The TypeScript Handbook

自分の成長を感じつつも、まだ踏み込めていない領域があります。そろそろちゃんと公式ページを読んで、「ちゃんとドキュメント読んでる人」にならんといかんな、と思います。

TypeScriptの仕様をちゃんと読んで把握すること、必要なときに公式ページを引用できること。型レベルプログラミングの文脈だけでなく、エンジニアとして大切な姿勢だと思います。

まとめ

型レベルプログラミングについて語る時に僕が語ることを書きました。長くなってしまった。

私自身もまだまだTypeScriptについて学ぶことが多いと感じつつも、
これを読んで型を自在に扱える仲間がひとりでも多くなって欲しいという気持ちです。

最後まで読んで頂き、ありがとうございました。

Discussion