# TypeScriptと仲良くなる
はじめまして、初投稿です。
私は約半年前から現場でReact、TypeScriptを扱うプロジェクトにアサインしています。
当時は、1行改修するにも丸一日かかるようなチュートリアルレベルでした、、
そんな半年前の自分に向けてTypeScriptで躓いた構文をまとめたいと思います。
若干ボリューミーに見えますが、簡単なコードが多いだけですw
① typeの書き方
まずは基本
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を作る
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;
見慣れない構文keyof
、typeof
ですが、一つずつ見ると
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のプロフィールが寂しいので追加で
hobby
とfavoriteFood
を任意で設定出来るようにしましょう
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
だったところをfirstName
とlastName
に分ける事になった場合、
どちらも型としては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で書くと、開発効率が良くなるのはもちろんですが、他の人が見たときに分かりやすいのもメリットだと思います。← とても大事 (頑張ります)
奥が深くまだまだ知らないこともあるので引き続き頑張ります。
最後まで見ていただきありがとうございました!