🎯

【type-challengesに挑戦!】If の解答と解説

に公開

はじめに

この記事は、type-challenges の問題を解説するシリーズです。今回は If の問題に挑戦します。

問題

TypeScript の組み込み型を使わずに、条件分岐を行う If<C, T, F> 型を実装します。

If<C, T, F> は、条件 C を受け取り、Ctrue の場合は型 T を、false の場合は型 F を返します。Ctrue または false のいずれかで、TF は任意の型を指定できます。

例:

type A = If<true, 'a', 'b'>  // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'

解答

type If<C extends boolean, T, F> = C extends true ? T : F;

解説

ステップ 1: 型パラメータの定義

type If<C extends boolean, T, F>

3 つの型パラメータを定義しています:

  • C: 条件を表すブール値型(true または false
  • T: 条件が true の場合に返す型
  • F: 条件が false の場合に返す型

ステップ 2: C extends boolean の制約

C extends boolean

この制約により、C は必ず boolean 型(true または false)でなければなりません:

  • これにより、型安全性が確保されます
  • truefalse 以外の値を渡すとコンパイルエラーになります

型安全性の例

// ✅ OK: true は boolean
type Valid1 = If<true, 'a', 'b'>;  // 'a'

// ✅ OK: false は boolean
type Valid2 = If<false, 'a', 'b'>;  // 'b'

// ❌ エラー: string は boolean ではない
type Invalid = If<'true', 'a', 'b'>;
// Type 'string' does not satisfy the constraint 'boolean'.

ステップ 3: 条件型 C extends true ? T : F

C extends true ? T : F

この部分が条件型(Conditional Types)の核心です:

  1. C extends true: Ctrue 型であるかをチェック
  2. ? T : F: 三項演算子のような構文
    • Ctrue の場合は型 T を返す
    • Cfalse の場合は型 F を返す

具体例で見てみましょう

type Example1 = If<true, 'success', 'failure'>;

この場合、以下のように評価されます:

  1. Ctrue
  2. true extends truetrue(条件を満たす)
  3. 結果: 'success'
type Example2 = If<false, 'success', 'failure'>;

この場合の評価:

  1. Cfalse
  2. false extends truefalse(条件を満たさない)
  3. 結果: 'failure'

ステップ 4: 実践的な使用例

条件型を使うことで、型レベルでの分岐処理が可能になります:

// 数値型かどうかで異なる型を返す例
type IsNumber<T> = T extends number ? true : false;

type Test1 = IsNumber<42>;        // true
type Test2 = IsNumber<'hello'>;   // false

// If 型を組み合わせた例
type Result1 = If<IsNumber<42>, 'is number', 'not number'>;
// 'is number'

type Result2 = If<IsNumber<'hello'>, 'is number', 'not number'>;
// 'not number'

ステップ 5: エッジケースの理解

boolean 型(true | false のユニオン型)を渡した場合:

type BooleanVar = boolean;
type Result = If<BooleanVar, 'a', 'b'>;
// 'a' | 'b'(分配法則により両方の結果がユニオン型で返される)

これは、TypeScript の条件型が持つ分配法則(Distributive Conditional Types)によるものです:

  • booleantrue | false のユニオン型
  • 条件型は各ユニオンメンバーに対して分配される
  • If<true, 'a', 'b'> | If<false, 'a', 'b'>'a' | 'b'

まとめ

この記事では、type-challenges の If 問題を通じて、以下の TypeScript の重要な概念を学びました:

  1. ジェネリック型パラメータ: 再利用可能な型定義の作成
  2. 型制約 (extends): 型パラメータに制限を設けて型安全性を確保
  3. 条件型(Conditional Types): T extends U ? X : Y 構文による型レベルの条件分岐
  4. ブール値リテラル型: truefalse を型として扱う
  5. 分配法則(Distributive Conditional Types): ユニオン型に対する条件型の振る舞い

参考リンク

Discussion