1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【TypeScript】条件型T extends U ? X : Y——ExcludeとExtractの中身

1
Posted at

はじめに

この投稿は、TypeScript学習者が書いています。条件型の読み方と、ユーティリティ型のExcludeがユニオン型の要素ごとにどう展開されるかを、自身の理解のために整理します。

1. 条件型とは

条件型は次のように書かれます。

T extends U ? X : Y
  • T … 判定する型
  • U … 割り当て先として比べる型
  • XTUに割り当て可能なときの型
  • Y … 割り当てできないときの型

TUに割り当て可能ならX、そうでなければYになります。

type IsString<T> = T extends string ? true : false;

type A = IsString<"hi">;
// true

type B = IsString<number>;
// false

この例ではUstringXtrueYfalseです。

2. ユニオン型では要素ごとに分配される

Tがユニオン型のとき、条件型は各要素に分配されます。

type ToName<T> = T extends string ? "str" : "other";

type Names = ToName<string | number>;
// "str" | "other"

ToName<string | number>は、次と同じ意味です。

type Names = ToName<string> | ToName<number>;
// "str" | "other"

string | number全体がstringに割り当て可能かを一度に見るのではありません。全体判定ならnumberを含むので結果は"other"だけになります。実際は要素ごとに分岐し、結果をユニオン型でつなぎます。

3. Excludeの定義

TypeScript組み込みのExcludeは、次の条件型です。

type Exclude<T, U> = T extends U ? never : T;

Statusから"archived"を除く例です。

type Status = "draft" | "published" | "archived";

type Editable = Exclude<Status, "archived">;
// "draft" | "published"

第2節と同じく、Exclude<Status, "archived">は要素ごとに分かれます。

type Editable =
  | Exclude<"draft", "archived">
  | Exclude<"published", "archived">
  | Exclude<"archived", "archived">;

各要素で、その要素が"archived"に割り当て可能かを見ます。

// "draft" extends "archived" ? never : "draft"
// → "draft"

// "published" extends "archived" ? never : "published"
// → "published"

// "archived" extends "archived" ? never : "archived"
// → never

neverはユニオン型から消えるので、残りは"draft" | "published"です。

const ok: Editable = "draft";
const ng: Editable = "archived"; // 型エラー
// Type '"archived"' is not assignable to type 'Editable'.

ExtractExcludeと逆で、Uに割り当て可能な要素だけを残します。

type Extract<T, U> = T extends U ? T : never;

type Closed = Extract<Status, "archived" | "published">;
// "published" | "archived"

まとめ

  • 条件型T extends U ? X : Yは、TUに割り当て可能かで型を分岐します。
  • Tがユニオン型のとき、条件型は要素ごとに分配されます。全体を一度に判定するのではありません。
  • Exclude<T, U>は各要素をT extends U ? never : Tで評価し、neverになった要素を除きます。
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?