TypeScript: extends [アウトプット全くしてこなかったのでアウトプットする005]

自分のTypeScript力に全く自信を感じないため、`type challenges`をやって現在の自分の立ち位置を確かめようとしましたが、早速easy問題の1問目から挫折したのでアウトプットします。

ちなみに問題は以下です

https://www.typescriptlang.org/play?#code/PQKgUABBAsELQQAoEsDGBrS8491gRgJ4QCCAdgC4AWA9mcQGICuEAFAAICGlAZkwJQQAxIFwlQFi+wpmWR1h+JsgA2FOMjJYsQrREBXMYHlVDVEAivoH8GQD3xJwHYMgaPVAZwyAfhkBjDIGKGQFcMLgAYoMAHgAqADQQANIAfB6ASQyA-vKAFK6A2gyAWgyAgAwefh6A0gyAkQwewR6WgOsMgLcMgIsMLhGAvUaAX4qAmgyA0QzWEYD52oCjEYDqDIB+DNWAQAyGEIDR8oASDIAODL0eYxQAzlhqFACmAE48nKizEH40ACY0EADeWFAUyBSKswBcEBMU82oA5vsQG7MTqNcADod055fXZHdQUKgaABbV4nOYbc74Gg0E7cLAAX16FEIr1W6y2iHmswAbshZgB3CAAXggAFlCN50P5NjQggByQ7HWZ0iAAHwgdMBILBsw2dNCvUBZEuEAoNPO6JomJxeMJJL2-3+jJO5zpAGFYWQIPNoUC6QF7gDgaDZuDzktFBNZgaoIioGMPL1QhAAOJHAASTHwgHMGQBdHoBYqLqgCx-qgUCivCanYDASaoKgAOgAVhN4zR5jdgNBgInOGAQMAwIXQBAAPpl8sV8sQQDKDNXANYMgGaGeyASYYIoAMKMApoqlys9ksQfOF5GoskUtBUwIhZ0k7iEQtgYu9nsQRyAToZABMMgEaGewr7uLqsD5AgtMUXYQACiAEcmJxFEEzwAPVGoE-wiA8HVAjnsIezOBxm8nL8TzAEwhyWnSg4oqsqCcFaEzEhAADaWAPk+FA+Je16KBhj6zM+vIAIxBOSlLUls9LKsyoTUTa564c+GFXjeOFobyABMxGjr4koUUcJwsuynLGjyfLUaEtHRhA34THAsz0SoCw6vMWAkWOZG0hylECRyXImuC2l0mo2I3sgokGgAuoWMwLEsKxrDSuxYJRXxXLcWCPM8bwfGQLk-H8EC6SJkLQpqYCImA1mLMsqyoXh4IEY5Bx8WcFyub8YVWZQNnRXRrEbGxiWislvluUa3KmrywUwrMcLhUWIC7nufaAITWlgro4gDDDPkjV7v2BagFgzqAMeRgAq3hEgCOioAkObBqG4aRtGsYJsmqbppmwDcBM+ILNmuZQMNY2ANGRtQhmGEZRjGzxLSmaYZlmEwwqBMjCoNECALoMliAGtyliAE1RgAyGSdc3nYtSbXatOZ5gWYBAA

問題の意味から既にわからずすぐ答えを見たのですが
答えもよくわからず、その理由として自分が今まで目を背けてきた`extends`と`in`を使用していましたのでこの際ちゃんと勉強しようと思いました。
この記事ではまずextendsについてまとめます。

## extendsとは

Genericsで渡される型に対して制約をつけるものだそうです。

例えば以下の関数はジェネリクスに何も制約がついていないのでどんな方でも指定することができます。
今回はboolean型を入れています。

```ts
const returnValue = <T>(value: T): T => value;
returnValue<boolean>(true);
```

ただこのジェネリクスに対して制約をつけることができます。それが`extends`です。

以下はextendsを使用してジェネリクスに渡す型を`number`型と`string`型に限定しています。

```ts
const returnValue = <T extends number | string>(value: T): T => value;
```

ここで

```ts
const returnValue = <T extends number | string>(value: T): T => value;
returnValue<boolean>(true);
```

ジェネリクスにboolean型を渡すと
型を検知して怒ってくれます。

![スクリーンショット 2022-03-05 10.21.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/4d79919e-2ef4-a536-f4b0-c00d1783942a.png)

## もうちょっと踏み込んでみる
ジェネリクスに制約なしで関数内で引数のプロパティ名を使用しようとするとジェネリクスにプロパティ`name`があることが担保されていないため怒られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/694b54b4-0bb7-fd77-d227-74306442e0ca.png)

ここで以下のようにnameプロパティがある型を作成し、extendsでジェネリクスに渡される型には`name`プロパティがあることを担保してあげるとエラーが消えます。

```ts
type Student = { name: string }
const getStudentName = <T extends Student>(student: T): string => student.name
```

また以下のように渡す型の名前がtypoしていたりするとエラーを出してくれます。

```ts
const me = { name: 'cawauchi' }
type ErrorStudentType = { nam: string }
getStudentName<ErrorStudentType>(me)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/216b375b-e028-61aa-328c-fa7141a2edb2.png)

以下は通ります。

```ts
const me = { name: 'cawauchi' }
type AdequateStudentType = { name: string, height?: 176 }
getStudentName<AdequateStudentType>(me)
```

extendsすごいですね。型エラー出してくれるので業務でも使える部分あったらどんどん使っていきたいです。


## 参照
https://github.com/type-challenges/type-challenges

https://typescriptbook.jp/reference/generics/type-parameter-constraint

https://qiita.com/k-penguin-sato/items/9baa959e8919157afcd4#%E5%9E%8B%E5%BC%95%E6%95%B0%E3%81%AB%E5%88%B6%E7%B4%84%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B

強くなりたい!!!!!!!!!!