0Pricing
TypeScript Academy · レッスン

TypeScriptにおけるHKTの問題

ジェネリックな型コンストラクターが難しい理由を理解します。

「TypeScriptにおけるHKTの問題」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。

高カインド型とは

高カインド型(HKT)は、具体的な型ではなく、型コンストラクターを抽象化します。型コンストラクターとは、ArrayやPromiseのように、実際の型になるために型引数を必要とするものです。

Arrayだけでは型ではありません。Array<string>は型です。Arrayは型に対する関数であり、HKTを使うと、このような関数に対してジェネリックになれます。

type StringArray = Array<string>;
type NumberArray = Array<number>;
// Array by itself is a type constructor, not a type

カインドの概要

値に型があるのと同じように、型コンストラクターにはカインドがあります。numberのような通常の型のカインドは*です。Arrayのカインドは* -> *で、1つの型を渡すと型が返ります。このような型コンストラクターに対してジェネリックになることを「高カインド」と呼びます。

type ValueLike = number;        // kind *
// Array needs one argument:    kind * -> *
// Map needs two arguments:     kind * -> * -> *

目標:Functor&lt;F&gt;

HKTをサポートする言語では、1つのmapを持つ単一のFunctor<F>抽象化を記述でき、配列、オプション、Promiseなど任意のコンテナで利用できます。1つのインターフェースで、多くのコンテナに対応できます。

interface Wish_Functor<F> {
  map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
}
// F<A> here is the wish - and TypeScript rejects it

問題点

TypeScriptは、型パラメーターを引数に適用することをサポートしていません。Fがジェネリックパラメーターの場合、F<A>とは記述できません。コンパイラーは「Type F is not generic」というエラーを出します。

// interface Functor<F> {
//   map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
// }
// Error: Type F is not generic

TS にない理由

TypeScriptの型パラメーターは一階であり、型コンストラクターではなく具体的な型を対象とします。「Fは1つの型引数を受け取るもの」と表す構文がないため、F<A>はコンパイラーにとって意味を持ちません。

// You can pass number, string, User as F...
// but not Array, not Promise (the constructors themselves)

具体的な問題点

HKTがない場合、コンテナごとにmapを重複して定義する必要があります。配列用、Option用、Promise用にそれぞれ1つずつ必要です。ロジックは同じですが、型システムではそれらを統一できません。

declare function mapArray<A, B>(fa: A[], f: (a: A) => B): B[];
declare function mapOption<A, B>(fa: A | null, f: (a: A) => B): B | null;
// Same shape, but no way to abstract over the container

表現したいこと

AのコンテナとA -> Bという関数を受け取り、コンテナの型を維持したままBのコンテナを返す、1つのシグネチャが必要です。ArrayはArrayのまま、OptionはOptionのままになります。

// Wish: map<F, A, B>(fa: F<A>, f: (a: A) => B): F<B>
// where F is preserved across the call

他の言語

HaskellとScalaにはHKTが組み込まれているため、Functor、Applicative、Monadのような型クラスを表現できます。TypeScriptでは、同じ能力を近似するための回避策が必要です。

// Haskell: class Functor f where fmap :: (a -> b) -> f a -> f b
// TypeScript: needs an encoding trick (next lessons)

エンコーディングの考え方

標準的な回避策はデファンクショナライゼーションです。Fを直接適用する代わりに、各コンテナに文字列タグ(URI)を与え、タグと引数を具体的な型に対応付けるレジストリを用意します。型の適用を検索に置き換えるのです。

// Instead of F<A>, we write Kind<F, A> where F is a URI string
// and a registry resolves it to the real type

これから作るもの

これからのレッスンでは、fp-ts形式のHKTエンコーディングを段階的に構築します。URItoKindレジストリ、Kindによる検索、そして登録済みの任意のコンテナでmapを使える汎用Functorを作ります。

// Roadmap:
// 1. Type constructors via URI strings
// 2. Kind<F, A> resolution
// 3. Generic Functor + instances

知っておく価値

このエンコーディングを自分で書く機会はほとんどありませんが、fp-tsやEffectのようなライブラリはこれに依存しています。この仕組みを理解すると、それらの型を読み、コンテナに対する汎用的な抽象化を書き、型システムにできることとできないことを理解できるようになります。

// Recognizing Kind<F, A> in library code is the payoff

クイックチェック

HKTの問題についての理解度を確認しましょう。

まとめ

高カインド型の問題について学びました。

  • HKTは具体的な型ではなく、Arrayのような型コンストラクターを抽象化します。
  • TypeScriptの型パラメーターは第一階のものなので、F<A>は使用できません。
  • そのため、1つのmapを持つ汎用Functorを作れません。
  • URIタグとレジストリを使ったエンコーディングが解決策です。

次は、URI文字列を使って型コンストラクターを定義します。

よくある質問

「TypeScriptにおけるHKTの問題」レッスンは無料ですか?

はい。「TypeScriptにおけるHKTの問題」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。

「TypeScriptにおけるHKTの問題」で何を学びますか?

ジェネリックな型コンストラクターが難しい理由を理解します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

TypeScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「TypeScriptにおけるHKTの問題」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このTypeScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. TypeScriptにおけるHKTの問題
  2. 型コンストラクターの定義
  3. 軽量HKTパターン
  4. ジェネリックなFunctorとMapper
← TypeScript Academyに戻る