結論
数値enumは extends number
, 文字列enumは extends string
すればよい
.ts
function F2<Collection extends string | undefined>(item: Collection) {
return item;
}
F2<Colors | undefined>(undefined);
F2<Colors | undefined>(Colors.Blue);
(TypeScript version: v4.1.3)
前提
TypeScript で enum 型を使うべきでなく union type を使うべきなのは承知しています。
参考: https://www.kabuku.co.jp/developers/good-bye-typescript-enum
それでもライブラリの兼ね合いなどでenumに依存せざるを得ないため、enumでの型の挙動を調べたメモになります。
enumの挙動についてはこちらの記事が相当詳しかったです。
https://2ality.com/2020/01/typescript-enums.html
実験
文字列enumと数値enumを用意します
.ts
export enum Colors {
Red = 'red',
Green = 'green',
Blue = 'blue',
}
export enum Numbers {
One = 1,
Two = 2,
}
とりあえず型変数で受けてみます
.ts
function F1<Collection>(item: Collection) {
return item;
}
// 数値enumでは strict check にならない
F1<Numbers>(Numbers.One); // ok
F1<Numbers>(1); // よくないことにok(なので数値enumは非常に使うべきでない)
// 文字列enum で strict check ができる
F1<Colors>(Colors.Red); // ok
F1<Colors>('blue'); // error
// Argument of type '"blue"' is not assignable to parameter of type 'Colors'.
本題。これに制約を加えます。
単純に undefined も指定できるようにしてみます。
.ts
function F2<Collection extends string | undefined>(item: Collection) {
return item;
}
F2<Colors>(Colors.Blue); // ok
F2<Colors>(undefined); // これは単に型変数の指定が間違っている
// Argument of type 'undefined' is not assignable to parameter of type 'Colors'.(2345)
F2<Colors | undefined>(undefined); // ok
F2<Colors | undefined>(Colors.Blue); // ok
F2<Colors | undefined>('blue'); // error
// Argument of type '"blue"' is not assignable to parameter of type 'Colors | undefined'.(2345)
// ↓2つはもちろんだめ
F2<Colors | undefined>(1); // error
F2<Numbers | undefined>(1); // error
というわけで extends string
すれば文字列enumを受けることができるみたいです。
一応数値enumのほうも置いておきます。
.ts
function F3<Collection extends number | undefined>(item: Collection) {
return item;
}
F3<Numbers | undefined>(Numbers.One); // ok
F3<Numbers | undefined>(undefined); // ok
F3<Numbers | undefined>(1); // よくないことにこれも通る
F3<Numbers | undefined>('hoge'); // error
// Argument of type '"hoge"' is not assignable to parameter of type 'Numbers | undefined'.(2345)