TypeScript の条件型 extends ってなに？



## 1. 条件型とは

<!--

ある型 `T` が型 `U` の **部分型** であるとは何かについて考えます。言い換えれば、以下の `Extends<T, U>` が `true` となるような `T`, `U` について考えていきます。

  -->

以下、色の付いているサンプルコードは [TypeScript: TS Playground](https://www.typescriptlang.org/play) で、コピペで動作します。変数 `Result` の上をマウスでホバーすると型 `true` が表示されてわかりやすいです。

```ts
//
// T が U の部分型であった場合 true を返す条件型 Conditional Type
//
type Extends<T, U> = T extends U ? true : false

//
// リテラル型はプリミティブ型の部分型
//
type Result0 = Extends<114514, number>  // true
type Result1 = Extends<45450721, number>  // true
type Result2 = Extends<'Kemono Friends', string>  // true
type Result3 = Extends<'serial experiments lain', string>  // true
type Result4 = Extends<true, boolean>  // true
type Result5 = Extends<false, boolean>  // true
```


https://qiita.com/domodomodomo/items/6586b9794b3798f53ebb



## 2. union distirbutioin

`Extends<0, 0 | 1>` は `true` になります。しかし `Extends<0 | 1, 0>` は `boolean` になります。`true` でもなければ `false` でもありません、なぜでしょうか？

```ts
type Extends<T, U> = T extends U ? true : false
type Result0 = Extends<0, 0 | 1>  // true
type Result1 = Extends<0 | 1, 0>  // boolean
```

`T extends U` の `T` が Union 型だった場合、Union 型の要素１つ１つに分解して `extends` を計算してしまうからです。

```ts
type Extends<T, U> = T extends U ? true : false
type Result1 = Extends<0 | 1, 0>  // boolean
// type Result1 = ( Extends<0 | 1, 0>                                              )
// type Result1 = ( 0 | 1 extends 0 ? true : false                                 )
// type Result1 = ((0     extends 0 ? true : false) | ( 1 extends 0 ? true : false))
// type Result1 = ((          true                  |             false           ))
// type Result1 = ( true | false                                                   )
// type Result1 = boolean
```

対策として以下のように配列 `[]` で括ると Union Distribution が起こりません。

```ts
type Extends<T, U> = T[] extends U[] ? true : false
type Result0 = Extends<0, 0 | 1>  // true
type Result1 = Extends<0 | 1, 0>  // false
```

また Union Distribution が起こるのはジェネリクスを使用したときのみで、ベタ書きすれば Union Distribution は起こりません。

```ts
type Result0 = 0 extends 0 | 1 ? true : false  // true
type Result1 = 0 | 1 extends 0 ? true : false  // false
```


<!-- 
以下の記事から知りました。本当に本当にありがとうございます。

* [TypeScriptの型初級 - Qiita](https://qiita.com/uhyo/items/da21e2b3c10c8a03952f#conditional-type%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bunion-distribution)
* [TypeScriptの型演習 - Qiita](https://qiita.com/uhyo/items/e4f54ef3b87afdd65546#4-3-union%E3%81%AF%E5%AB%8C%E3%81%A0)
* [TypeScriptの型演習（解答・解説編） - Qiita](https://qiita.com/uhyo/items/0e7821ce494024c98da5#4-3-union%E3%81%AF%E5%AB%8C%E3%81%A0)



-->

### ◯ 御礼

uhyo さんの記事からこの動作をしりました。本当に本当にありがとうございます。リンクを貼ると先方の記事にリンクができてしまうのでタイトル名のみ掲載いたします。

* TypeScriptの型初級 - Qiita
* TypeScriptの型演習 - Qiita
* TypeScriptの型演習（解答・解説編） - Qiita

書籍も買わせていただきました。

* [プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで](https://gihyo.jp/book/2022/978-4-297-12747-3)


### ◯ 追記

union distribution を避ける際には T[] より [T] が公式の見解らしいです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TypeScriptのconditional typesで分配の発生を避ける方法はいろいろあるが、公式には [X] extends [Y] ? ... の形を推奨しているのか。<br>しかも「square bracketsで囲む」という説明の仕方でそうなのという気持ち（？）<a href="https://t.co/Sex1i4f3aI">https://t.co/Sex1i4f3aI</a>.</p>&mdash; 🈚️うひょ🤪✒📘 TypeScript本発売🫐 (@uhyo_) <a href="https://twitter.com/uhyo_/status/1721012908178694465?ref_src=twsrc%5Etfw">November 5, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 3. extends
### ◯ 機能

TypeScript では `extends` と書かれていた場合、5 つの機能があります。

1. class のための `extends`
2. interface のための `extends`
3. Generics を使った型の制約のための `extends`
4. Conditional Types を使った条件分岐のための `extends`
5. 4 における infer を使った推論のための `extends`


2~5 の機能についてリンク先で解説されています。
<!--
本稿の目的は、部分型とは何かであり extends の機能の解説ではないことに留意してください。
 -->
* [TypeScriptのextendsってなんなん？ - Zenn](https://zenn.dev/nbr41to/articles/7d2e7c4e31c54c)






### ◯ 意味

上記のように `extends` には 5 つの機能がありますが、

```
T extends U
```

と書かれていた場合、 常に `T` 型のオブジェクトは、 `U` 型のオブジェクトが書かれているところでも使えることを表しています。

> TypeScript ではここを含めていくつかの場面で S extends T という構文が登場しますが、これは常に「S は T の **部分型** である」という意味です。(P. 101 脚注)
> [プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで](https://gihyo.jp/book/2022/978-4-297-12747-3)

部分型っていつ使うんですか？どんなときに便利なんですか？って聞かれたら `extends` のときに使います、`extends` を使うときに便利ですと答えるのがよいのかなと思います。



<!--

本稿では `T extends U` と書かれていた場合、`T` を部分型、`U` を上位型と呼ぶことにします。いろいろ呼び方があるようなのですが、よくわからない...

-->






## 4. 公式ドキュメント

いやいや、お前の「`T` 型のオブジェクトは、 `U` 型のオブジェクトが書かれているところでも使える」って表現はあってんのかよ？という感じがするのですが。以下は公式ドキュメントの条件型 Conditional Types の項目からの抜粋を見ると、正しくはないけど、妥当かなという気がします。

```
SomeType extends OtherType ? TrueType : FalseType;
```
> **extendsの左側の型が右側の型に代入可能な場合、** 最初のブランチ（「true」ブランチ）の型が得られ、そうでない場合、後のブランチ（「false」ブランチ）の型が得られる。
> **When the type on the left of the extends is assignable to the one on the right,** then you’ll get the type in the first branch (the “true” branch); otherwise you’ll get the type in the latter branch (the “false” branch).
> [TypeScript: Documentation - Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)

条件型, Conditional Type は募集要項の１つに挙げられています。このことから条件型は TypeScript の学習のマイルストーンのひとつになるかなと思いました。

> * 必須スキル
>   * 型関数や、conditional typeなどを利用したTypeScriptでの開発経験
>
> [ちょっと株式会社 > 求人一覧フロントエンド(Jamstack)エンジニア](https://herp.careers/v1/chot/5y3cHQkAMhRM)


https://qiita.com/domodomodomo/items/6586b9794b3798f53ebb