お題
Exclude<T, U>
を使用せず、ユニオン型T
からU
で指定したユニオン型を取り除いたユニオン型を返す型MyExclude
を実装する。
やりたいこと
type result = MyExclude<"a" | "b" | "c", "a"> // "b" | "c"
解答
type MyExclude<T, U> = T extends U ? never : T;
解説
処理の流れ
-
<T, U>
ユニオン型T
と、取り除きたい型U
を引数にとるようにする。 - Conditional Typesによって評価を行う。
-
U
の場合は、never
を返す -
U
ではない場合は、そのままT
の値を返す
-
そもそもExclude<T,U>
とは...
ユニオン型T
からU
で指定した型を取り除いたユニオン型を返すユーティリティ型
type Grade = "A" | "B" | "C" | "D" | "E";
type PassGrade = Exclude<Grade, "E">; // "A" | "B" | "C" | "D";
ユニオン型の条件分岐の場合に何が起こる?
Conditional TypesのUnion distributionと言う性質により、各要素に対して評価が行われる(分配法則)。
// MyExclude<"a" | "b" | "c", "a"> の場合
("a" extends "a" ? never : "a") | ("b" extends "a" ? never : "b") | ("c" extends "a" ? never : "c")
-> never | "b" | "c"
-> "b" | "c"
Conditional Typesとは...
参考記事
Exclude<T,U>
Exclude | TypeScript入門『サバイバルTypeScript』
Union distribution
ユニオン分配 (union distribution) | TypeScript入門『サバイバルTypeScript』
今回の問題