はじめに
前回
TypeScriptの真骨頂は「静的型付け」だけではない。
文脈に応じて変化する“文脈依存の型推論”すなわち 制御フロー解析(Control Flow Analysis) こそが、TypeScriptの型システムを強力たらしめている。
本稿では以下の要素を中心に解説する:
- 制御フロー解析とは何か?
- 型の絞り込み(Type Narrowing)の具体例
- 型ガードの設計手法
制御フロー解析とは
制御フロー解析とは、プログラムの“実行経路”を型システムが理解し、値の型を絞り込む機能である。
以下のようなコードがその典型である。
function printLength(value: string | null) {
if (value !== null) {
console.log(value.length); // ✅ TypeScriptは value が string と認識する
}
}
このように if 文の条件をもとに TypeScript は value の型を string に絞り込んでいる。
型の絞り込み(Type Narrowing)
TypeScript は以下のような構文で自動的に型の絞り込みを行う:
typeof
function log(x: string | number) {
if (typeof x === "string") {
console.log(x.toUpperCase());
} else {
console.log(x.toFixed(2));
}
}
instanceof
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function speak(pet: Dog | Cat) {
if (pet instanceof Dog) {
pet.bark();
} else {
pet.meow();
}
}
in 演算子
function move(animal: { fly: () => void } | { swim: () => void }) {
if ("fly" in animal) {
animal.fly();
} else {
animal.swim();
}
}
これらは全て、TypeScriptの「文脈を読む」力に基づいている。
ユーザー定義型ガード(Type Predicate)
より高度な型絞り込みを実現するために、開発者が独自に型ガードを定義できる。
function isString(value: unknown): value is string {
return typeof value === "string";
}
function handle(value: unknown) {
if (isString(value)) {
console.log(value.toUpperCase());
}
}
この構文 value is string が 型述語(Type Predicate) であり、TypeScript に対して型情報を明示的に与えている。
実務では、複雑な型や外部データ(例:APIレスポンス)を扱う際に極めて有用である。
never型と制御フローの網羅性
never は、型の絞り込みが“すべて消費された”ときに現れる特殊な型である。
type Shape = { kind: "circle"; radius: number } |
{ kind: "square"; side: number };
function area(shape: Shape) {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
default:
const _exhaustiveCheck: never = shape; // ❌ 新しい型が追加されるとコンパイルエラー
return _exhaustiveCheck;
}
}
このようにして「すべてのパターンを網羅していること」をコンパイル時に保証できる。
まとめ
| 技法 | 用途 |
|---|---|
typeof, instanceof, in
|
組み込み型ガードによる絞り込み |
| 型述語関数 | より厳密かつ再利用可能な型判定 |
never を使った網羅性保証 |
安全性と拡張性の担保 |
制御フロー解析は、TypeScriptの型システムの中核であり、型安全な設計を支える屋台骨である。
この仕組みを正しく理解し活用することで、実装の堅牢性と可読性を飛躍的に高めることができる。
次回は「ジェネリクス完全攻略:柔軟かつ安全な型抽象化の設計術」をテーマに、TypeScriptの汎用性を支える設計手法に迫る。