LoginSignup
13
10

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-12-02

 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つずつ解説

const Sex = {
  man: '',
  woman: '',
};

constで定義されているのでこれ単体だとただのオブジェクトです。

type SexType = keyof typeof Sex;

見慣れない構文keyoftypeofですが、一つずつ見ると

typeof Sex;
/*
    ↓オブジェクトの構造がそのままtypeになる
  {
    man: '男',
    woman: '女',
  }  
*/
keyof typeof Sex;
/*
    ↓typeofでtypeになったSexのkey(文字列)のみを持つtypeになる
  'man' | 'woman' 
*/

文字で説明すると逆にややこしい気がしますが、、

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だったときにを画面に表示することもとても楽になります。

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

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

③ 任意の型を追加する

Engineerのプロフィールが寂しいので追加で
hobbyfavoriteFoodを任意で設定出来るようにしましょう

type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: LanguageType[]
  otherInfo: {
    hobby: string | undefined
    favoriteFood: string | undefined
  }
};
type Engineer = {
  name: string
  age: number
  sex: SexType
  languages: LanguageType[]
  otherInfo: {
    hobby?: string
    favoriteFood?: string
  }
};
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をまとめて理解する

④ typeを繋げる

type Name = {
  name: string;
}
type Age = {
  age: number
}
type Engineer = Name &
    Age & {
    sex: SexType
    languages: LanguageType[]
    otherInfo: Partial<OtherInfo>
  };

こんな感じで細かくtypeを定義して&でつなげてひとまとめにできます。
もちろんName、Age以外も同じように定義しておいてすべて&でつなげることも可能です。

おまけ  

BrandedType

type Engineer = {
  firstName: string
  lastName: string
  age: number
  sex: SexType
  languages: LanguageType[]
};

nameだったところをfirstNamelastNameに分ける事になった場合、
どちらも型としてはstringで区別することはできません。

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

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

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10