TypeScriptの高度な型(Utility Types、Conditional Types)

## はじめに
私がまとめたTypeScriptに関する記事一覧になります。もし興味がありましたらご覧になってください。
* [TypeScriptの基本的な文法・型](https://qiita.com/Hirohana/items/d93820bd6bc514aec116 "TypeScriptにおける基本的な文法・型")
* [TypeScriptの関数・クラスに関する文法と型](https://qiita.com/Hirohana/items/553353c82c8107a3358b "TypeScriptの関数・クラスに関する高度な文法と型")
* [TypeScriptの高度な型(Utility Types、Conditional Types)](https://qiita.com/Hirohana/items/9c85e65c6e09b9f8b5c8 "TypeScriptの高度な型(Utility Types、Conditional Types")

今回は、**TypeScriptの高度な型(Utility Types、Conditional Types**)についての記事になります。

## Utility Types
> ユーティリティ型(utility type)は、型から別の型を導き出してくれる型のこと。functionが実行時の世界の関数だとしたら、ユーティリティ型は型の世界の関数というイメージ。TypeScriptで使える既存の型から新しい型を作成するための便利な関数のようなもの。

以下の記事で丁寧にまとめられてたので、引用させていただきました。

https://qiita.com/k-penguin-sato/items/e2791d7a57e96f6144e5

https://typescriptbook.jp/reference/type-reuse/utility-types


## Conditional Types
> 三項演算子のような書き方を用いながら、条件分岐を型の定義に導入できる1つの文法。これによって動的な型を定義することが可能となる。

Conditional Typesを学ぶことによってUtility Typesがどのように定義されているか理解できるようになります。

以下、Conditional Typesで使われているキーワードについて一部解説します。

### Mapped Types
> Conditional Typesの文法で使用されている以下のような構文のこと。Mappted Typesを使用することにより、既存の型から型を取り出して独自の型を定義する事が可能となる。

```typescript
type Partial<T> = {
    [P in keyof T]?: T[P];
};
```
* **keyof** ・・・Tというオブジェクトの型の全てのプロパティのkeyを文字列リテラル型のunion types(合併型)で引っ張ってきます。

* **in**・・・上記のkeyofで取り出された文字列リテラルで構成されたunion型の要素を1つ1つ取り出します。つまり、`P in keyof T` のPにはunion型の要素である文字列リテラルが入っています。

```typescript: Mapped-Types.ts
// Mapped Types
type Profile = {
  name: string;
  age: number;
};

// Utility TypesのPartialを使って型を抽出。
type PartialProfile = Partial<Profile>;
 
// Conditional Typesを使って独自の型Optionalを定義。
// 中身はPartialと同じ。
type Optional<T> = { [P in keyof T]?: T[P] };
type OptionalProfile = Optional<Profile>;
```

### extends
> TypeScriptで使えるキーワードの1つ。`T extends U`という構文があった場合、TはUの部分型(上位互換)であるという意味になる。

```typescript: extends.ts

// Compatibilityはtrue
type Compatibility = string extends string | number | boolean ? true : false;

// NonCompatibilityはfalse
type NonCompatibility = string extends number | boolean ? true : false; 
```

* string型はstring | number | booleanに対して互換性があるので、Compatibilityにはtrueが渡ってきます。

* string型は number | booleanに対して互換性がないので、NonCompatibilityにはfalseが渡ってきます。

### Distributive Conditional Types
> `T extends U ? X : Y` というConditional TypesのTにユニオン型が渡って来た時の構文のこと。

T extends U ? X : YのTの型引数にA | B | Cが渡された場合T extends U ? X : Yは(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)のように展開されます。

```typescript: distributiveConditionalTypes.ts
type T = A | B | C;
type Exclude<T, U> = T extends U ? never : T;
 
// 上記の右辺の中身を分解すると以下と同義になる。
(A extends U ? never : A) | (B extends U ? never : B) | (C extends U ? never : C)
```
### infer
> inferキーワードは、TypeScriptのconditional typesで使用される特殊なキーワード。
型の一部を抽出し、それを新しい型パラメータとして利用。これにより、型の一部を柔軟に推論して再利用することが可能となる。

Conditional Typesでは無数の条件式を書くことができて、その条件式の中で型を拾い上げたい場面があります。戻り値の型をなんとかして拾い上げたいと思ったときに、どんな型かわからないけどピックアップしたい、そういう制御ができるのが`infer R`です。この場合戻り値の型がRとして扱われます。

inferの意味は直訳すると察知する、推論するという意味です。つまり型として推論した結果をRに代入するという意味になります。

```typescript: infer.ts
function add(a: number, b: number) {
  return a + b
}

type ReturnTypeFromAdd = ReturnType<typeof add>; // number型
 
type MyReturnType<T extends (...args: any) => any> = T extends (
  ...args: any
) => infer R
  ? R
  : any;

type MyReturnTypeFromAdd = MyReturnType<typeof add>; // number型
```
* 上記のReturnTypeFromAdd関数はUtility Typesの1つである`ReturnType`を使い、関数の戻り値の型(number)を抽出する関数です。
* MyReturnTypeは`infer`と`extends`を使って関数の戻り値の型を抽出するConditional Types。`ReturnType`のConditional Typesの構造と全く同じです。

## まとめ
* `Utility Types`はTypeScriptのコードで利用できる型変換を容易に行える便利な関数の集まりです。
* `Conditional Types`は`Utility Types`の裏側で動いている仕組みで、多くの`Utility Types`は`Conditional Types`をベースにして作られています。

## おわりに
最後まで記事をご覧いただきありがとうございました。

間違いなどありましたらご指摘いただけると幸いです。:bow:
## 参考

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript-%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-Boris-Cherny/dp/4873119049

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80-%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7-Software-Design-plus/dp/4297127474

https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a

https://knmts.com/as-a-engineer-52/

https://www.typescriptlang.org/static/TypeScript%20Types-ae199d69aeecf7d4a2704a528d0fd3f9.png