TypeScript用語覚書

TypeScriptを現場で使うことは増えてきたが、記法の正式名称を聞いた時に混乱しないようにまとめていくことにした。

## 型推論
![スクリーンショット 2022-06-05 22.10.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/8b25b95c-2349-fea5-f9f8-54ed6f2ffeeb.png)
メソッド、letやconstなどの定数・変数を定義したときにその名前にホバーしたときに、表示してくれる。
(この場合は、引数と返す値の型がnumberで指定されているので、numberと表示される。)

基本的に、型推論で十分な場合は、以下の型アサーションや型アノテーションは不要。

## 型アノテーション
定数やメソッドの方を定義すること。

:::note
名前: 型名
:::

のように書く。

```typescript:例
const text: string = "あいうえお";

let nun: number = 123;

var saa: Array<string> = ['頭を垂れて躓え。', '土下座して靴を舐めろ']

function hogehoge(): string {
  return "Hello, World!";
}

```

## 型アサーション
メソッドや引数の型を上書きすること。
基本的に特別な事情がない限りは使わない。
例えば、number型の値を引数としてstring型の値を返すメソッドが決まった値のいずれかを返すことが分かっていて、そのどれかに該当する値を列挙型(後日列挙型についてはまとめる)として定義しておき、そのメソッドの引数に型アノテーションとして型を上書きする場合など。

```typescript: (例)
type strEnum = "black" | "white" | "red";
const colors = (x: number): strEnum => {
  if (x < 0) return "black";
  else if (x === 0) return "white";
  else return "red";
};
```

## オプショナル
値の型を定義する時に値に?をつけること。

:::note
名前?: 型名
:::

のように書く。

```typescript: (例)
const muzanMessage = (text?: string): string => {
  if (text) return "頭を垂れて蹲え。"
  return "頭頭を垂れずに蹲うな。"
}
```

## 列挙型
変数の値を一つのまとまりにすること。

```typescript: (例)
type PokemonType =
  | "ノーマル"
  | "ほのお"
  | "みず"
  | "くさ"
  | "でんき"
  | "こおり"
  | "かくとう"
  | "どく"
  | "じめん"
  | "ひこう"
  | "エスパー"
  | "むし"
  | "いわ"
  | "ゴースト"
  | "ドラゴン"
  | "あく"
  | "はがね"
  | "フェアリー"
```

## Tuple型
配列の型と個数が固定されている型のこと。

```typescript: (例)
const vsRaceValue : [string, number] = ["イーブイの進化系の種族値の合計", 525] 
```

配列の個数、値が来る順番が明確である場合に使うことがある。

## any型
値にどんな型も当てはめられるようにする。

```typescript: (例)
let metamon: any = "リザードン"
```

anyを使うと基本的にTypeScriptの恩恵がなくなってしまうので、あまり使わない。

## unknown型
どんな値が来るか分からない場合に使う。
anyとは似て非なる型。

![スクリーンショット 2022-06-12 22.13.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/e24f3072-6ed8-691e-89f9-1678f97e4534.png)

型が決まっているものに代入できなかったりする。

unknown型は例えば、

```typescript
function deoxysForm(val: unknown): string {
  if(typeof val === 'number') return "ノーマルフォルム"
  else if(typeof val === 'string') return "アタックフォルム" 
  else if(typeof val === 'boolean') return "ディフェンスフォルム" 
  return "スピードフォルム"
}
```

のように引数の型が予想できない場合に使用することが多い。

## typeof
指定した値の型と同じものを指定すること。
決して、typeOfではないので、注意。

```typescript: SkillPpの型にtypeofでskillPpの型を指定する
let skillPp: number
type SkillPp = typeof skillPp
```
と書くと、
![スクリーンショット 2022-10-01 15.27.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/b049d1a5-aea9-4bbd-6dcd-86f411a02963.png)
skillPpの型が型アノテーションで「number」で指定されているので、SkillPpの型はnumberとなる。

### constで指定した値をtypeofで指定するとどうなるか？

```typescript: constで指定した値をtypeofで指定する
const dioStand = "ザ・ワールド"
type DioStand = typeof dioStand
```
こうすると、
![スクリーンショット 2022-10-01 15.51.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/1b12836e-8ca4-a8bd-54ed-8c92232121af.png)
DioStandの型は"ザ・ワールド"になる。
constは定数なので、代入した値がLyteral Typesとしてその変数の型として指定される。
そして、その変数をtypeofで型を指定すると、constに代入した値がそのまま型になる。

### constで変数を指定しつつ、型アノテーションもするとどうなるか

```typescript: constで変数を指定しつつ、型アノテーションもする
const dioStand:string = "ザ・ワールド"
type DioStand = typeof dioStand
```
こうすると、
![スクリーンショット 2022-10-01 15.54.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/6f49832d-f83e-069d-107d-09e69684355f.png)

DioStandの型はstringになる。
constのパラメータを型アノテーションで指定すると、型アノテーションで指定した型が優先される。

### オブジェクトを定義した時に、そのオブジェクトをベースに新たに値を定義したい時


```typescript: 
const jojoPart4MainCharacter = {
  body: "東方仗助",
  stand: "クレイジー・ダイヤモンド"
}

const jobjojoPart4StrongEnemy: typeof jojoPart4MainCharacter = {
  body: "吉良吉影",
  stand: "キラー・クイーン"
}
```

新たに作成したオブジェクトのパラメータ(jobjojoPart4StrongEnemy)の型に、元にしたいオブジェクト(jojoPart4MainCharacter)を指定すればよい。

## keyof
オブジェクトのパラメータ名をLiteral Typesとして取得できるようにする。

## オブジェクトはどうやって定義する？
ポケモンずかんで考えてみる

### パラメータが明確な場合
APIで取得した値など、返ってくる値がわかっている場合は、このパターン。
```typescript:パラメータが明確な場合
const pokemon1 : {
    type1: string,
    type2?: string,
    name: string,
    no: number,
    exclusiveSkill: boolean,
    exclusiveSkillName?: string,
 } = {
    type1: "ドラゴン",
    type2: "ゴースト",
    name: "ドラパルト",
    no: 887,
    exclusiveSkill: true,
    exclusiveSkillName: "ドラゴンアロー"
} 
```

※
◯ポケモンにはタイプが1個か2個の場合がある→type1は必須にして、type2はオプショナル
◯専用わざがあるポケモンがいる→exclusiveSkillは必須にしつつ、exclusiveSkillNameはオブジェクトに含まれなくてもよくしている。

### パラメータが不明瞭の場合
どんなパラメータにするかが曖昧な場合はこちら。

string | boolean | number

```typescript: パラメータが不明瞭の場合
const pokemonData: Record<string, unknown> = {
  name: "セグレイブ",
  type1: "ドラゴン",
  type2: "こおり",
  no: 951,
  exclusiveSkill: true,
  exclusiveSkillName: "きょけんとつげき",
};

const pokemonData2: { [key: string]: unknown } = {
  name: "バンギラス",
  type1: "いわ",
  type2: "あく",
  no: 248,
  exclusiveSkill: false,
};

```

パラメータにセットする値が決まっている場合は、

```typescript: パラメータにセットする値が決まっている
const pokemonData: Record<string, string | number | boolean> = {
  name: "セグレイブ",
  type1: "ドラゴン",
  type2: "こおり",
  no: 951,
  exclusiveSkill: true,
  exclusiveSkillName: "きょけんとつげき",
};

const pokemonData2: { [key: string]: string | number | boolean } = {
  name: "バンギラス",
  type1: "いわ",
  type2: "あく",
  no: 248,
  exclusiveSkill: false,
};

```

のようにunknownをstring | number | booleanのように決めてもいいかもしれない。

できるかぎり、型はまとめておいた方がいいので、以下のように型を決めてしまってもいいかもしれない。

```typescript: ポケモンのタイプの型
type TypeOfPokemon = {
    name: string
    type1: string
    type2?: string
    no: number
    exclusiveSkill?: string 
}
```


## 参考記事
https://typescriptbook.jp/reference/values-types-variables/tuple