TypeScriptには keyof
というオペレータがある。
例えば、
type Point = { x: number; y: number };
という、型を定義した場合、
> type Point = { x: number; y: number }; undefined > type P = keyof Point; undefined > var point: P = "x" undefined > var point: P = "y" undefined > var point: P = "z" <repl>.ts:8:5 - error TS2322: Type '"z"' is not assignable to type 'keyof Point'. 8 var point: P = "z" ~~~~~
このように、keyをUnion typeに変換することが出来る。
それでは、以下のようなコードにおいてMapishはどのようにUnion Typeに変換されるだろうか。
type Mapish = { [k: string]: boolean }; type M = keyof Mapish;
普通に考えれば、type M = number
になるはずだ。
しかし試しに打ち込んでみると、var mapish: M = "2" がコンパイルエラーにならず意図通りにはならない。
> var mapish: M = 1 undefined > var mapish: M = 2 undefined > var mapish: M = "2" undefined // コンパイルエラーになって欲しい > var mapish: M = [] <repl>.ts:14:5 - error TS2322: Type 'never[]' is not assignable to type 'string | number'. // string | number と認識されている
これは上記の最後の行で Type 'never[]' is not assignable to type 'string | number'
と記述されていることから分かる通り、type M = string | number
型に変換されていることが原因だ。
これはなぜかというと、JavaScriptオブジェクトのkeyは常に文字列として扱われているからだ。
具体例でいうと、obj[0]
は常にobj["0"]
と等しいということ。
やはりTypeScriptを使うときは常にJavaScriptを意識しておいたほうが心構えとしてよさそうだ。