【TypeScript】列挙型
列挙型とは
列挙型は、Java や C#などと同じく名前付きの定数を定義するためのものです。
定義にはenum
を使用し、定数名はすべて大文字とします。
enum Status {
SUCCESS,
WARN,
ERROR,
}
switch (s) {
case Status.SUCCESS:
console.log('SUCCESS')
break
case Status.WARN:
console.log('WARNING')
break
case Status.ERROR:
console.log('ERROR')
break
}
TypeScript の列挙型は、以下より説明する数値と文字列によって定義できます。
数値列挙型
定数の値に数値を設定します。
enum Status {
SUCCESS = 1,
WARN = 2,
ERROR = 3,
}
const s = 1
console.log(s === Status.SUCCESS) //true
console.log(s === Status.WARN) //false
数値は省略することができ、この場合 0 からの連番が設定されます。
enum Status {
SUCCESS, //0
WARN, //1
ERROR, //2
}
途中で数値を設定した場合は、その数値からの連番が設定されます。
enum Status {
SUCCESS, //0
WARN = 3, //3
ERROR, //4
}
文字列列挙型
定数の値として文字列を設定します。 数値型と違い、省略することはできません。
enum Status {
SUCCESS = 'success',
WARN = 'warning`,
ERROR = 'error'
}
const s = 'success'
console.log(s === Status.SUCCESS) //true
console.log(s === Status.WARN) //false
open ended
同じ名前の列挙型を定義した場合、その結果はマージされます。
enum Status {
SUCCESS,
}
enum Status {
WARN = 1,
ERROR,
}
2 つ目以降に定義する最初の値は、省略することができません。
定数列挙型
次のような列挙型があるとします。
enum Status {
SUCCESS,
WARN,
ERROR,
}
const s = Status.SUCCESS
これを JavaScrpt にコンパイルすると、以下のようになります。
var Status
;(function (Status) {
Status[(Status['SUCCESS'] = 0)] = 'SUCCESS'
Status[(Status['WARN'] = 1)] = 'True'
Status[(Status['ERROR'] = 2)] = 'ERROR'
})(Status || (Status = {}))
const s = Status.SUCCESS
このように列挙型に該当するオブジェクトが作成されます。 値を使用する際は、このオブジェクトを参照する必要があります。
では次のようにconst
を付与します。
const enum Status {
SUCCESS,
WARN,
ERROR,
}
const s = Status.SUCCESS
これを JavaScript にコンパイルすると、以下のようになります。
const s = 0
列挙型に該当するオブジェクトは作成されず、その値のみが必要な箇所で使われます。
見てわかる通り、const
を付与することでパフォーマンスの向上が見込めます。
--preserveConstEnums
を設定することでconst
を付与しても、列挙型に該当するオブジェクトが作成されるようになります。
const assertion
実は列挙型には問題があり、使用しない方が良いという説があります。
参照:https://www.kabuku.co.jp/developers/good-bye-typescript-enum
参照:https://engineering.linecorp.com/ja/blog/typescript-enum-tree-shaking/
以下に簡単な問題点をあげます。
const enum Status {
SUCCESS,
WARN,
ERROR,
}
function func(s: Status) {
console.log(s)
}
func(Status.SUCCESS) //0
func(10) //10
func
の引数にはStatus
を設定していますが、実は数値であればエラーなく実行することができてしまいます。
ここで、列挙型の代わりに使用するのが const assertion です。 const assertion は、TypeScript3.4 から導入された機能で、推測される型の不変性を担保するためのものです。 よくわからないと思うので、以下の例を見てください。
let x = [0, 1]
type XT = typeof x //number[]
let y = [0, 1] as const
type YT = typeof y //readonly [0, 1]
x
はnumber[]
の型を持ちますが、as const
を付与したy
はreadonly
のタプル型となります。
つまり、x
の値は変更可能ですが、y
は変更不可となります。
これをオブジェクトで使用してみます。
オブジェクトにas const
を付与すると、各プロパティにreadonly
が付与された型となります。
const obj = {
x: 0,
y: 1,
z: 2,
} as const
type T = typeof obj
//{
// readonly x: number,
// readonly y: number,
// readonly z: number
//}
では、const assertion を使用して列挙型を置き換えてみます。
const Status = {
SUCCESS: 0,
WARN: 1,
ERROR: 2,
} as const
type Status = typeof Status[keyof typeof Status] // 0 | 1 | 2
function func(s: Status) {
console.log(s)
}
func(Status.SUCCESS) //0
func(10) //Error
列挙型より定義が少しだけ手間かもしれませんが、先程あげた問題を解決することができます。