🎯
【type-challengesに挑戦!】If の解答と解説
はじめに
この記事は、type-challenges の問題を解説するシリーズです。今回は If の問題に挑戦します。
問題
TypeScript の組み込み型を使わずに、条件分岐を行う If<C, T, F> 型を実装します。
If<C, T, F> は、条件 C を受け取り、C が true の場合は型 T を、false の場合は型 F を返します。C は true または false のいずれかで、T と F は任意の型を指定できます。
例:
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)でなければなりません:
- これにより、型安全性が確保されます
-
trueやfalse以外の値を渡すとコンパイルエラーになります
型安全性の例:
// ✅ 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)の核心です:
-
C extends true:Cがtrue型であるかをチェック -
? T : F: 三項演算子のような構文-
Cがtrueの場合は型Tを返す -
Cがfalseの場合は型Fを返す
-
具体例で見てみましょう:
type Example1 = If<true, 'success', 'failure'>;
この場合、以下のように評価されます:
-
Cはtrue -
true extends true→true(条件を満たす) - 結果:
'success'
type Example2 = If<false, 'success', 'failure'>;
この場合の評価:
-
Cはfalse -
false extends true→false(条件を満たさない) - 結果:
'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)によるものです:
-
booleanはtrue | falseのユニオン型 - 条件型は各ユニオンメンバーに対して分配される
-
If<true, 'a', 'b'> | If<false, 'a', 'b'>→'a' | 'b'
まとめ
この記事では、type-challenges の If 問題を通じて、以下の TypeScript の重要な概念を学びました:
- ジェネリック型パラメータ: 再利用可能な型定義の作成
-
型制約 (
extends): 型パラメータに制限を設けて型安全性を確保 -
条件型(Conditional Types):
T extends U ? X : Y構文による型レベルの条件分岐 -
ブール値リテラル型:
trueとfalseを型として扱う - 分配法則(Distributive Conditional Types): ユニオン型に対する条件型の振る舞い
参考リンク
- https://github.com/type-challenges/type-challenges
- https://github.com/type-challenges/type-challenges/blob/main/questions/00268-easy-if/README.md
- https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
- https://www.typescriptlang.org/docs/handbook/2/generics.html
- https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types
Discussion