TypeScript (以下 ts) には型の書き方がいろいろあります.
しかしながら型の書き方が分からないときにはどうやってググったらいいのかわからないので困ることも多いです.
もちろん公式ドキュメントを全部読めばこの記事にある内容は必要ないのですが、残念ながら公式ドキュメントは英語なので読まれないことが多いです.
この記事ではよく使う書き方をズラズラ書いていきますので困ったときのリファレンスとして使われることを想定して書いておきます.
Object の型を作る
js の時代は Object の取り扱いは変な型を入れないようにするために神経を使いました.
const person = {
name: "田中",
age: 100
}
ts では以下のように型を定義しておけば.
interface Person {
name: string
age: number
}
こんな感じに書くことができてとても安全です. 値の型が間違っているとコンパイルエラーになります.
const person: Person = {
name: "田中",
age: 100
}
// or
const p = {
name: "田中",
age: 100
} as Person
残念ながら以下のように書くとコンパイルエラーにならないので const person: Person
形式で書くのがおすすめです.
const p = {
} as Person
型のエイリアスを作りたい
type
キーワードを使って宣言します. 以下の例では string
のエイリアスとして UserID
という型を作りました. この場合、 UserID は string 型と同じ型を持ちます.
type UserID = string
この書き方に何の意味があるかというと A の書き方より B の書き方のほうが自明で分かりやすいからです.
// A
const findUserById = (id: string) => { /* ... */}
// B
const findUserById = (id: UserID) => { /* ... */}
文字列の enum っぽいのを作りたい
これも type
キーワードを使います. 例えばこんな感じです.
type Fruit = "apple" | "banana"
// これを使ってこんな関数を定義して
const eat = (fruit: Fruit) => console.log(`Eat ${fruit}`)
// こんな風に呼ぶことができます.
eat("apple")
// Fruit に定義していない文字列を渡すとエラーになります.
eat("gorilla")
通常、関数の引数に文字列を直接書くのは typo の危険性があってお勧めできないのですが type
キーワードを使って予め定義しておけば間違った文字列を書いたときにコンパイルエラーになるので安心です.
ちなみに数値も扱えます. こうすればマジックナンバーっぽいけど安全な書き方ができます.
type Num = 1 | 2 | 3
型を混ぜることもできます.
type Num = 1 | 2 | "san"
更に柔軟にこんな書き方もできます. js の頃はこんな風な型を受け取る関数がありましたね.(((;꒪ꈊ꒪;)))
でも ts なら安全です.
type Num = 1 | 2 | string
Object のある key の値の型を取り出したい
例えば以下のような乗り物を示す型があったとして、ある関数で kind だけ受け取りたい場面があるとします.
interface Vehicle {
name: string
kind: "car" | "bike" | "train"
}
そんな場合にこんな風に書くのは NG です. string
を受け取ると typo の危険性があります.
const doSomethingForKind = (kind: string) => {}
しかしながら
type VehicleKind = "car" | "bike" | "train"
という型を宣言するのは僕が異常なまでなめんどくさがり屋なので書きたくないです.
前置きが長くなりましたが、そんなときには以下のように書けます.
const doSomethingForKind = (kind: Vehicle["kind"]) => {}
楽ちんですね. また型だけ取り出したい場合は以下のように書くこともできます.
type VehicleKind = Vehicle["kind"]
VehicleKind
を宣言してから Vehicle
を宣言するか、あるいはその逆にするかはそのアプリケーションの考え方によるのですがこんな書き方もできますよという感じです.
型を足し算する
React をやってると複数の sub component をまとめた親コンポーネントを作る状況がよくあります.
そんな場合には sub component の Props が増えたり減ったりすると親コンポーネントの Props も編集する必要があって面倒です. そんなときに使えるテクニックです.
interface SubComponent_A_Props {
name: string
}
interface SubComponent_B_Props {
age: number
}
// 超めんどい
interface ParentComponentProps {
name: string
age: number
}
この ParentComponentProps
は以下のように書けます.
type ParentComponentProps = SubComponent_A_Props & SubComponent_B_Props
楽ちんですね.
interface
と type
ts では型を宣言するのに interface と type の2種類の方法があります.
選び方としてはまず interface
で書けるか検討します.
書けない場合は type
を使います.
理由としては interface
は継承したりできて拡張性が高いのですが、 type
の方はできることが限られていて拡張性が低いからです.
ここから先は Mapped Types というもう少し複雑な Topic になります.
これが使えるとどんどん ts が楽しくなってくるのでぜひ覚えてください. 最初の頃は難しく感じますが慣れてくると恐ろしく柔軟に型を定義しつつ型安全にコードを書くことができます.
特に js は恐ろしく柔軟に作られているライブラリが多いのでそれらを ts から使おうとするとこの辺の知識が必要になってくると思います.
またここでは Mapped Types とはなんぞやという説明は省いて実際によく使うテクニックをいろいろ書くので使いながら覚えてみてある程度分かってきたら公式ドキュメントを見てきちんと理解してみてください.
以下 TODO... φ(•ᴗ•๑)