計算言語としての型
型システムを純粋関数型言語として理解します。
「計算言語としての型」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。
型は言語です
TypeScriptには、隣り合って存在する2つの言語があります。1つは、すでにご存じの値レベルのJavaScriptです。もう1つは型レベルで、完全にコンパイル時に実行されます。このコースでは、2つ目の言語でプログラミングする方法を学びます。
型システムは、小さく純粋な関数型言語です。型を入力として与えると、型を出力として計算します。その内容が実行時に残ることはありません。
type Greeting = "hello";
type Loud = Uppercase<Greeting>;
// Loud is "HELLO" - computed by the type system型を入力し、型を出力する
ジェネリック型は本質的に型から型への関数です。型パラメーターが引数にあたり、本体が戻り値にあたります。
以下のBoxedは型Tを受け取り、それをラップするオブジェクト型を生成します。Tを渡すパラメーターだと考えてください。
type Boxed<T> = { value: T };
type A = Boxed<number>; // { value: number }
type B = Boxed<string>; // { value: string }ジェネリックは関数です
値レベルの関数と型レベルの関数を比較してみます。形はほぼ同じで、パラメーターを入力し、1つの結果を出力します。
- 値:
const id = (x) => x - 型:
type Id<T> = T
型レベルのIdは、渡されたものをそのまま返します。
type Id<T> = T;
type X = Id<boolean>; // boolean
type Y = Id<"abc">; // "abc"実行時コストはない
型レベルの処理はすべて、コードが実行される前に消去されます。JavaScriptの出力には、型の計算の痕跡が一切含まれません。型がどれほど複雑でも、実行中のプログラムにパフォーマンス上のコストはありません。
このため、型レベルプログラミングは無料と呼ばれることがあります。コンパイラーに影響するだけで、バンドルには影響しないからです。
type Pair<T> = [T, T];
const p: Pair<number> = [1, 2];
// Compiled JS is just: const p = [1, 2];
console.log(p);複数のパラメーター
型レベルの関数は、通常の関数と同じように複数のパラメーターを受け取れます。ここではMergeが2つのオブジェクト型を受け取り、それらを結合します。
AとBが与えられたとき、両方のすべてのプロパティを持つオブジェクトを返す、と読み取れます。
type Merge<A, B> = A & B;
type User = { id: number };
type Named = { name: string };
type NamedUser = Merge<User, Named>;
// { id: number; name: string }パラメーターのデフォルト値
型パラメーターには、関数のデフォルト引数と同じように、デフォルト値を設定できます。呼び出し側で引数を省略すると、デフォルト値が使われます。
type List<T = string> = T[];
type A = List; // string[]
type B = List<number>; // number[]制約はガードです
extends を使った制約は、渡せる型を制限します。これは、関数の引数を使用する前に検証することに相当する、型レベルの仕組みです。
HasId は、すでに id プロパティを持つ型だけを受け付けるため、本体では安全にそれを読み取れます。
type GetId<T extends { id: number }> = T["id"];
type A = GetId<{ id: number; name: string }>; // number
// GetId<{ name: string }> would be a compile error注釈だけでなく計算
初心者は、値にラベルを付けるためだけに型を使います。型レベルプログラミングでは、型を使って答えを計算します。たとえば、組み込みの ReturnType ユーティリティ型は関数型を調べ、結果の型を取り出します。
type Fn = (a: number) => string;
type R = ReturnType<Fn>; // string
type Fn2 = () => boolean;
type R2 = ReturnType<Fn2>; // booleanプロパティに対するマッピング
マップ型を使うと、オブジェクト型のすべてのプロパティを変換できます。これは型言語におけるループです。Stringify は、すべての値の型を string に変換します。
type Stringify<T> = { [K in keyof T]: string };
type Input = { a: number; b: boolean };
type Out = Stringify<Input>; // { a: string; b: string }純粋で決定的
型言語は純粋です。同じ入力からは常に同じ出力型が生成され、副作用はありません。ミューテーションも、IOも、時間もありません。この純粋性によって、型レベルプログラムは予測可能になり、組み合わせて使いやすくなります。
純粋であるため、数学について考えるときと同じように、代入によって型について考えられます。
type Square<T extends { area: number }> = T["area"];
// Always the same result for the same input shapeなぜ重要か
この第2の言語を習得すると、コンパイラーが自動的に強制するルールを記述できます。たとえば、有効なルート、網羅的な switch、安全な文字列操作、誤用できないAPIなどです。このコースの残りでは、そのためのツールボックスを構築します。
重要な考え方:型は型言語における値であり、ジェネリックは関数です。
type NonEmpty<T extends unknown[]> =
T extends [unknown, ...unknown[]] ? T : never;
// Encodes a rule: the tuple must have at least one element理解度チェック
計算言語としての型について、理解度を確認しましょう。
まとめ
TypeScriptの型は、コンパイル時に実行される純粋関数型言語を形成していることを学びました。
- ジェネリックは関数です。型を受け取り、型を返します。
- パラメーターはデフォルト値と
extends制約をサポートします。 - マップ型はプロパティをループ処理します。
- すべては消去されるため、実行時のコストはありません。
次は、この言語に if 文、つまり条件型を導入します。
よくある質問
「計算言語としての型」レッスンは無料ですか?
はい。「計算言語としての型」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。
「計算言語としての型」で何を学びますか?
型システムを純粋関数型言語として理解します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
TypeScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「計算言語としての型」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このTypeScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。