項目7 型を値の集合として考える
型に含まれる値の集合をドメインと呼ぶ(本書で用いるワード)
number型にはあらゆる数値が当てはまる
ドメインが異なれば、扱える値も異なる
最小の集合はから集合で値を含まない
TypeScriptではnever型がそれに当たる
neverは型階層の一番下に位置することからボトム型と呼ばれる
ドメインが空であるため、never型を持つ変数には値を代入できない
code:ts
const x: never = 12;
// ~ Type 'number' is not assignable to type 'never'.
// 型 'number' を型 'never' に割り当てることはできません。
never型の次に小さい集合は、単一の値を扱うリテラル型
code:ts
type A = 'A';
type B = 'B';
type Twelve = 12;
複数の値を持つ型は、リテラル型のユニオンとして扱う
ユニオン型のドメインは、ユニオン型を構成する型の和(ユニオン)
code:ts
type AB = 'A' | 'B';
type AB12 = 'A' | 'B' | 12;
never型の対極に存在するのがunknown型
unkwon型はJavaScriptのすべての値が含まれ、すべての型はunknown型に代入可能
トップ型と言われる
assignableという単語は、TypeScriptのエラーに登場し、値の集合の文脈では「〜メンバー」または「〜の部分集合」のどちらかを意味する
型チェッカーが行っていることの多くは、ある集合が別の集合の部分集合であるかをテストすること
型のドメインは無限になりえる
無限の範囲を限定的にするために、型の命名などで型の利用意図を伝える必要がある
hr.icon
型を値の集合として考えると、型に対する演算が理解しやすくなる
&演算子は2つの型のインターセクション(交差)を計算する
型演算は、値の集合に適用される
code:ts
interface Person {
name: string;
}
interface Lifespan {
birth: Date;
death?: Date;
}
type PersonSpan = Person & Lifespan;
型の集合から考えたときにextendsの意味
「〜の部分集合」を意味する(assignableと同様)
extendsは通常、interfaceにフィールドを追加するために使われるが、元の型の値の部分集合になってさえすればどんな使い方も可能
code:ts
interface NullyStudent {
name: string;
ageYears: number | null;
}
interface Student extends NullyStudent {
ageYears: number;
}
元の値の型を拡大、部分集合でない型を当てはめようとするとエラーになる
code:ts
interface StringyStudent extends NullyStudent {
ageYears: number | string; // エラーになる
}
extendsはジェネリック型の成約を表現するのにも使える
項目15 型演算とジェネリック型を使って重複を避ける
hr.icon
サブタイプ
ある型のドメインが他の型のドメインの部分集合であることを表現するための別の言い方
サブタイプは、街道構造として表現できるが、値の集合という観点からベン図のほうが適切
https://scrapbox.io/files/6808a394d5543f48352bf449.png
code:ts
interface Vector1D { x: number; }
interface Vector2D extends Vector1D { y: number; }
interface Vector3D extends Vector2D { z: number; }
hr.icon
型を集合として考えることで、配列とタプルの関係も明確になる
number[]は[number, number]の部分集合にはならない
code:ts
const list = 1, 2;
// ^? const list: number[]
const tuple: number, number = list;
// ~~~~~ Type 'number[]' is not assignable to type 'number, number'
タプルは長さをもっているので異なる長さの値の型を識別できる
code:ts
const triple: number, number, number = 1, 2, 3;
const double: number, number = triple;
// ~~~~~~ 'number, number, number' is not assignable to 'number, number'
これは、TypeScriptが2要素の数値の配列を{0: number, 1:number}ではなく、{0: number, 1:number, length: 2}としてモデリングしているため
hr.icon
TypeScriptは部分集合/サブタイプの関係を元に代入可能性を常にテストしている
ただ、型の等価性チェックはほとんど行っていない
そのため型のテストを書くことが難しい
table:TypeScriptの用語と集合論の用語
TypeScriptの用語 集合論の用語
never ∅ (空集合)
リテラル型 単一の要素からなる集合
値がTに代入可能である 値 ∈ T (メンバーである)
T1がT2に代入可能である T1 ⊆ T2 (部分集合である)
T1がT2を拡張する T1 ⊆ T2 (部分集合である)
T1 | T2 T1 ∪ T2 (ユニオン)
T1 & T2 T1 ∩ T2 (インターセクション)
unknown 全体集合
#TypeScript