type-challenges 5日目: 43-Exclude

問題 & 解答

組み込みのExclude<T, U>を自前で実装する

Conditional Typesの分配法則を用いて、次のように記述する。

type MyExclude<T, U> = T extends U ? never : T

例えば

  • T"a" | "b" | "c" | "d"
  • U"c" | "d" | "e" | "f"

であるとき、まず"a"Uのサブセットではないので、Tつまり"a"が返る。 一つ飛ばして"c"Uのサブセットなので、neverが返る。

分配法則によりこれらの結果を結合したものが返るのでMyExclude<"a" | "b" | "c" | "d", "c" | "d" | "e" | "f">"a" | "b"をあらわす

調べたこと

Exclude型

差集合を表す型

// Exclude<UnionType, ExcludedMembers>

// (a, b, c)
type T0 = Exclude<"a" | "b" | "c", "a"> 
// type T0 = "b" | "c"

type T1 = Exclude<"a" | "b" | "c" | "d", "c" | "d" | "e" | "f">
// type T1 = "a" | "b"

TypeScript: Documentation - Utility Types

Conditional TypesとDistributive(分配法則)

  • Conditional types がGeneric型である時、Union型が渡された場合は、分配法則に従う。
// 各Tがanyでを満たせば`T[]`を返す
type ToArray<T> = T extends any ? T[] : never;

type StrArrOrNumArr = ToArray<string | number>;

StrArrOrNumArrでは、TとしてUnion型のstring | numberが与えられている。

// StrArrOrNumArrの右辺は次のようになる(ちょっと表現としては変だけど)
(string | number) extends any ? T[] : never

// 分配法則により次のように読み下せる
(string extends any ? string[] : never) | (number extends any ? number[] : never)

// anyはすべてを満たすので`StrArrOrNumArr`はこうなる
string[] | number[]

Buy Me A Coffeeikuma-tにお恵みを!