TypeScriptと仲良くなる(初心者向け)

#　TypeScriptと仲良くなる

はじめまして、初投稿です。

私は約半年前から現場でReact、TypeScriptを扱うプロジェクトにアサインしています。
当時は、1行改修するにも丸一日かかるようなチュートリアルレベルでした、、

そんな半年前の自分に向けてTypeScriptで躓いた構文をまとめたいと思います。
若干ボリューミーに見えますが、簡単なコードが多いだけですw

## ① typeの書き方
まずは基本

```engineer.ts
type Engineer = {
  name: string
  age: number
  sex: string
  languages: string[]
};

const engineer: Engineer = {
  name: 'ホゲ',
  age: 25,
  sex: 'man',
  languages: ['TypeScript', 'React', 'Java'],
};
```
typeはオブジェクトの型を定義しています。

typeを定義しなくてもオブジェクトは問題なく作れるのですが、
各valueに好きな値を入れられてしまうため、いつの間にか変テコなオブジェクトになっていて
なんかしらんけどバグってる。ってことになりかねません。

値の不正代入も防げて、IDEの入力補完も効くので型無しのJavaScriptよりも開発効率が良いと個人的に思います。

## ② オブジェクトからtypeを作る

```engineer.ts
const Sex = {
  man: '男',
  woman: '女',
};

type SexType = keyof typeof Sex;

type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: string[]
};
```

この構文も初めて見たときは何が起きているのかさっぱりでした。
結論としては`sex`に入れられる値を`man`または`woman`の文字列だけに制限しています


1つずつ解説

```ts
const Sex = {
  man: '男',
  woman: '女',
};
```
`const`で定義されているのでこれ単体だとただのオブジェクトです。

```ts
type SexType = keyof typeof Sex;
```
見慣れない構文`keyof`、`typeof`ですが、一つずつ見ると

```ts
typeof Sex;
/*
　　　　↓オブジェクトの構造がそのままtypeになる
  {
    man: '男',
    woman: '女',
  }　　
*/
keyof typeof Sex;
/*
　　　　↓typeofでtypeになったSexのkey(文字列)のみを持つtypeになる
  'man'　|　'woman' 
*/
```
文字で説明すると逆にややこしい気がしますが、、

```ts
type Engineer = {
  name: string
  age: number
  sex: SexType /* 'man' | 'woman' */
  languages: string[]
};

const engineer: Engineer = {
  name: 'ホゲ',
  age: 25,
  sex: 'weman' /* 怒られる */,
  languages: ['TypeScript', 'React', 'Java'],
};
```
もともと`string`だったところを`SexType`に置き換えると、
`man`, `woman`以外の文字列を入れようとするとコンパイルエラーになります。

コンパイルエラーになる以外にも、
sexが`man`だったときに`男`を画面に表示することもとても楽になります。

```ts
console.log(engineer.sex); /* man */
console.log(Sex[engineer.sex]);  /* 男 */
```

同じように`LunguageType`を作るのもいいですね

## ③ 任意の型を追加する
Engineerのプロフィールが寂しいので追加で
`hobby`と`favoriteFood`を任意で設定出来るようにしましょう

```ts
type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: LanguageType[]
  otherInfo: {
    hobby: string | undefined
    favoriteFood: string | undefined
  }
};
```
```ts
type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: LanguageType[]
  otherInfo: {
    hobby?: string
    favoriteFood?: string
  }
};
```
```ts
type OtherInfo = {
  hobby: string
  favoriteFood: string
};

type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: LanguageType[]
  otherInfo: Partial<OtherInfo>
};
```
3通り書きましたが、typeとしてはすべて同じ内容になります。
3番めの`Partial<>`ですが、これは`Utility Types`の一つで使いこなせると便利なやつです。
詳しくははこちらの方の記事がおすすめです。
[【TypeScript】Utility Typesをまとめて理解する](https://qiita.com/k-penguin-sato/items/e2791d7a57e96f6144e5)

## ④ typeを繋げる

```ts
type Name = {
  name: string;
}
type Age = {
  age: number
}
type Engineer = Name &
    Age & {
    sex: SexType
    languages: LanguageType[]
    otherInfo: Partial<OtherInfo>
  };
```
こんな感じで細かくtypeを定義して`&`でつなげてひとまとめにできます。
もちろんName、Age以外も同じように定義しておいてすべて`&`でつなげることも可能です。


## おまけ　　
### BrandedType

```ts
type Engineer = {
  firstName: string
  lastName: string
  age: number
  sex: SexType
  languages: LanguageType[]
};
```
`name`だったところを`firstName`と`lastName`に分ける事になった場合、
どちらも型としては`string`で区別することはできません。

```ts
type FirstName = string & { _brand: 'FirstName' };
type LastName = string & { _brand: 'LastName' };

type Engineer = {
  firstName: FirstName
  lastName: LastName
  age: number
  sex: SexType
  languages: LanguageType[]
};
```
`string`に`{ _brand: (型名等) }`という他と被らないプロパティを付けることで、区別出来るようになります。

`BrandedType`は自身で把握出来る程度の規模であれば無くてもいいのかなと思いますが、
細部まで型が定められていると、参照が増えたり複雑な構造になった際にもミスを防げるし、自分以外の人が見たときにも分かり易いんじゃないかなと思います。

## まとめ
今ではどれも当たり前のように使えるようになりましたが、
当時は本当に分からなくて頭に定着するまで何度も調べていました、、笑

TypeScriptで書くと、開発効率が良くなるのはもちろんですが、他の人が見たときに分かりやすいのもメリットだと思います。← とても大事 (頑張ります)

奥が深くまだまだ知らないこともあるので引き続き頑張ります。
最後まで見ていただきありがとうございました！