import * as M from ""
で読み込んだモジュールをブラケット記法[]
で使いたい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//module_a export const contents_a = ...; export const contents_b = ...; export const contents_c = ...; //module_b import * as M from "./module_a" export const someFunc = (name: string) => { M.contents_a; //ドット表記法なら問題ない M[name]; //この書き方はエラー /* expression of type 'string' can't be used to index type 'typeof import("..."). No index signature with a parameter of type 'string' was found on type 'typeof import("..."). ts(7053) */ } |
こんな感じで引数(変数)に対応したモジュールを使いたい場合にどうするか。
リテラル型のunion型で定義する
モジュールにないものにアクセスする可能性があるのでダメなのはわかる。
1 2 3 |
(name: "contents_a" | "contents_c" | "contents_c") => { M[name]; } |
リテラルのunion
型でコンテンツを列挙すればブラケットでアクセス可能になる。
でもこれだと数が多いときにどうすればいいんだろう。
配列化してunion
化する
Object.keys(M)
でコンテンツ一覧を配列化できる。
配列からunion
型に変換する方法はあるだろうかと調べてみる。
➡TypeScript 3.4 で Array (string[]) を Union Type に変換する Tips
as const
でリテラル配列として定義したものをnumber
で制御してtypeof
でリテラル列挙してる感じだろうか。
Object.keys(M)
はas const
できないので結局string
になってしまいます。
keyof 演算子(ドキュメント)
Object
なんて使わなくてもkeyof
を使えばキー一覧のunion
型を得られるらしい。
1 2 |
(name: keyof M) => {} //名前空間 'M' を型として使用することはできません。ts(2709) |
import * as
で名前空間として定義したので型ではないと怒られる。
typeof
をかまして使う。
1 |
(name: keyof typeof M) => {} |
これで想定通りの動きになる。
なんとなく見た目は気になるけどシンプルに解決できた。