手を動かしながら学ぶ TypeScript Part 3 --高度な型
Tags: typescript
Published: 2022-04-25 18:43:05


## why

応用的な型の一つの記事では収まらなかったので。

---

## 参考
手を動かしながら学ぶ TypeScript
by SmartHR
SECTION-025 TypeScript の型や構文の紹介
P.277 ~

https://www.amazon.co.jp/%E6%89%8B%E3%82%92%E5%8B%95%E3%81%8B%E3%81%97%E3%81%AA%E3%81%8C%E3%82%89%E5%AD%A6%E3%81%B6-TypeScript-%E6%B8%A1%E9%82%89%E6%AF%94%E5%91%82%E6%A8%B9-ebook/dp/B09KZJXDN1

---

## 目次

1. generics
2. tupple
3. typeof
4. Index Signature
5. Mapped Types
6. keyof
7. enum
8. conditinal types
9. Partial
10. Requied
11. Omit


---

## Generics

受け取った型に応じた処理ができる？

```ts
function printMessage<T> (arg: T):T {
  console.log(typeof arg);
  console.log(arg);
  return arg
}

printMessage("text")
printMessage(33)
```

引数の型を表示して返す関数が作れる

```ts
ts-node generics.ts
string
text
number
33
```

"text" を渡せば string
33 を渡せば number が返ってくる

型をなんでも受け取って、なんの型かを返す関数は 
any でも同じことができてしまいそう

---

## tupple

完全に入るものが決まった型。

```ts
type bucket = string[]
const fruits:bucket = ['apple', 'banana', 'tomato']

type tuppleBucket = ['apple', 'banana']
const tuppleFruit:tuppleBucket = ['apple', 'kwi']
```

> Type '"kwi"' is not assignable to type '"banana"'

bucket は文字列のみがいくらでも入る配列だが
tuppleBucket は 'apple', 'banana', のみが入る型になった。

---

## typeof

```ts
const sayHello = (name: string) => {
  console.log(`Hello: ${name}`);
}
type sayHello = typeof sayHello
```

string が void で返る型を type に再代入することができる。
あまり普段使わなそう。
string, number, bool, などの単純な型を見る時には使えるが。

---

## Index Signature

key の名前と型、value の型
これらだけを決めて、型を使って入る数は自由にする。

https://zenn.dev/tsuboi/articles/ee43ddc5a2cd941de138#%E2%91%A0%E3%82%AD%E3%83%BC%E3%81%AE%E5%9E%8B%E3%81%AFstring%E5%9E%8B%E3%81%8Bnumber%E5%9E%8B

Tsuboi さんの記事が分かりやすかったので引用させてもらう

```ts
​type Ranking = {
  [rank: number]: string;
};
const ranking: Ranking = {
  1: "Mikasa Ackermann",
  2: "Reiner Brown",
  3: "Bertolt Hoover",
};
```

この例だと

* key のランクで数値型、
* value が文字列型
* 入る数は自由

と指定して、

* rank1: ミカサ
* rank2: ライナー
* rank3: ベルトルト

と値を入れることができる

---

## Mapped Types

ユニオン型からオブジェクトのキーを生成して型を作れるらしい。
用途不明。

---

## keyof

interface から各オブジェクトの key を取って ユニオン型にできる。

```ts
interface Cat {
  name: string,
  age: number
}
type CatKey = keyof Cat
```

この CatKey は "name" | "age" になる。

```ts
const NyaakoName:CatKey = "name"
const NyaakoAge:CatKey = "age"
const Tama:CatKey = { name: "Tama"} 
```

なので最後の Tama は

> Type '{ name: string; }' is not assignable to type 'keyof Cat'.

Cat の key たちには入りませんというエラーが出る。

---

## enum

列挙型

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80n0i5zfdlmqnsyxe283.png)

補完が効いて便利。

```ts
enum SIZE {
  S,M,L,
}

const myShirt = SIZE.M
const myLongShirt = SIZE[2]
const myPotato:SIZE = SIZE.L
```

SIZE.M でプロパティのように利用したり
SIZE[2] で配列のように利用したり
:SIZE と型として利用することともできる。
しかし、型の表記があってもなくても enum の中身以外入らないし、
型扱いされるので必要ないかも？

---

## Assertion Functions 

難解。未検証

---

## Conditional Types

条件によって変わる型。型の中でロジックを計算できるのが画期的そう。

https://zenn.dev/pvcresin/articles/073dc774eb241c

pvcresin さんのこの記事が分かりやすかった

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

変数の isOpen みたいなノリで条件を入れて型を作れる。
この場合はジェネリクスで型を引数から持ってきて、
string だったら true
違ったら false を返す型になっている。

```ts
type name = IsString<'kaede'>
type age = IsString<2>
```

isString を使って 'kaede' という文字列の型と
2 という数値の型を作る

数値でもエラーにならず作れてしまうが、

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xjrmvnaq9947jnd7h72.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dbu4j6dun5tqpeby9q2i.png)
  
型の名前をホバーすると、age では false が出ている。

---

## Partial

type name?:string のようにすると optional になって
その項目がなくてもエラーにならなくなるが

その型に後から

```ts
const VariableName: TypeName<Partial> = {}
```

とすると無理矢理 optional にできる。

---

## Required

Partial の逆。同じやり方で必須にできる。

---

## Omit

型オブジェクトの一部を無視して使用できる。

```ts
const variableName: Omit<TypeName, 'TypeItemName'> = {}
```

これで　TypeItemName を定義しなくても、無理矢理 TypeName の型を使うことができる。

```ts
type Turtle = {
  name: string,
  age: number,
}

const KameTaro: Omit<Turtle,'age'> = { name: "Kametaro"}
```

これで、age を無視して Turtle 型を使った変数を定義することができた。