TypeScript その1 型の基本
もはやフロントエンドを触る人にとってはTypeScriptは義務教育感があるので
今回はTypeScriptについて基本的な部分を調べてまとめておく
TypeScriptとは
所謂AltJSと呼ばれるもので、最近名前を聞かないが昔はCoffee Scriptが一世を風靡していた
AltJSで書いたコードを、素のJSに変換して使用する
(そんな面倒なことをするのは、素のJSが大規模開発に耐えられない貧弱な部分を補完してくれる恩恵があるから)
そんなAltJSの中で近年最も注目度が高く、実際に広く使われているのがTypeScriptである
型定義
素のJSでは型を使うことはできないが、TSには型が存在する
変数: 型
で型を定義する
let name: string = "hoge"
let count: number = 10
let users: string[] = ["taro", "kenji"] // let users: Array<string> = [〜] とも書ける
let users2: string[][] = [["hoge"], ["fuga"]] // 二次元配列
let multi: (number | boolean | string)[] = [1, false, "Tokyo"] // 複数種類の配列で、 | はorの意味
let multi2: [number, boolean, string] = [1, false, "hoge"] // tuple指定
let product: { name: string, price: number } = { name: "ルンバ", price: 98000 } // プロパティも指定したobject型
let product: {} = { name: "ルンバ", price: 98000 } // product: object じゃなくても実はよかったりする
型の種類は以下の通り
- boolean(true, false)
- number(1, 123, 9999)
- string("hakozaru")
- array([1, 2, 3])
- tuple
- 例えば
["hakozaru", 1234]
こんな配列があった場合、(string | number)[]
という指定をしても、順番までは考慮されない([1234, "hakozaru"]
でもエラーにならない) - なので
const arr: [string, number] = ["hakozaru", 1234]
と書くと順番まで型指定することができる - この指定の方法をタプル(tuple)と呼ぶ
- 例えば
- any
- void
- null
- undefined
- never
- object
- unknown
- 交差型(intersection)
-
以下のように既存の型定義を再利用することができる
type Prof1 = { name: string } type Prof2 = { age: number } // Prof1 | Prof2 のようにor条件も可能(その場合はnameかageがあればよい) type Prof3 = Prof1 & Prof2 const user: Prof3 = { name: 'hako', age: 99, }
-
- 共用体型(union)
-
以下のように定義することをunion型と呼ぶ
let value: number | string = 1 value = "hako"
-
- Literal
-
string
やnumber
では対象範囲が広すぎるような、ある特定の文字列、数値だけを代入可能にしたい時に使う// 日〜土までの文字列だけが入れられる let dayOfTheWeek: "日" | "月" | "火" | "水" | "木" | "金" | "土" = "日" dayOfTheWeek = "hako" // error! // 1〜12まで許可 let month: 1 | 2 | 3| 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 = 1 month = 13 // error!
-
- 列挙型(enum)
-
Railsなどでもおなじみの型
// { '0': 'Jan', 〜 '11': 'Dec', Jan: 0, 〜 Dec: 11 } みたいなオブジェクトが自動で定義される enum Months { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, } console.log(Months) // { '0': 'Jan', 〜 '11': 'Dec', Jan: 0, 〜 Dec: 11 } console.log(Months[0]) // Jan console.log(Months.Jan) // 0 // 0オリジンではなく、Janは1にしたい場合はオーバーライドもできる enum Months { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, } console.log(Months[1]) // Jan console.log(Months.Jan) // 1 // なお、Rubyのオープンクラスのように、必要に応じてあとから拡張することも可能 enum Months { Hoge = 123, Fuga = 999, }
-
関数への型定義
関数に対しては戻り値の型を指定することができ、
function hoge(): void {
console.log(987)
}
function fuga(): string {
return "abc"
}
のように書く
なお、上のhoge関数の例では return
を書いていないので、戻り値は存在しない
コンソールで見ると、undefinedと出るのでundefined型を指定したくなるが、
undefined型を指定した場合は、 return undefined
または return
と明示的にundefinedを返す必要がある
このように戻り値を指定していない場合はvoid型を指定しなければならない(anyでも可)
(ちなみに、void
型には undefined
も含まれるので、 let hoge: void = undefined
は問題なかったりする)
また、もし以下のように例外によって呼び出し元へ戻ってこないような関数の場合は never
型を使う
function hoge(msg: string): never {
throw new Error(msg)
}
interface
以下のようなオブジェクトを変数に格納することを考える
{
id: 123,
title: "title ~~~",
description: "hoge hoge hoge",
}
こいつはオブジェクトなので、定義は const data: object = { ... }
を指定してあげれば、問題なくコンパイルを通過する
確かにオブジェクトなので指定は間違ってはいないが、オブジェクトの中のものまでチェックしないとエラーの原因になる
そこで使うのがinterfaceというもので、以下のように定義して使用する
// オブジェクトの定義ではないので、末尾にカンマは不要
// セミコロンなら入れてもOK
interface Data {
id: number
title: string
description: string
}
const data: Data = { ... }
直感的に理解できると思うけど、オブジェクトの中身1つ1つに対して型を定義して、それに名前(Data)をつけている
言い換えると「オブジェクト型に名前をつけることができる」ということ
より正確に制約を課すことができるので、ガシガシ使っていきましょう
型エイリアス
type
を使って型にエイリアスを設定することもできる
type Mojiretu = string
const moji: Mojiretu = 'aaa' // moji: stringと同義
console.log(mojiretu) // => aaa
// interfaceに似てる
type Profile = {
name: string
age: number
}
const prof: Profile = { name: "hako", age: 999 }
console.log(prof) // => { name: "hako", age: 999 }
// typeofで既存の定義を引っ張ってくることもできる
type Hoge = typeof Profile