【TypeScript】interfaceの一つの要素を型で指定する方法
前置き
TypeScriptに完全に置き換える場合は、この内容は全く不要です。 JavaScriptをTypeScriptに書き換えるために、なるべく書き換えずに、かつ型安全にしていくためのものです。
元のコード(JavaScript)
var ConstantsTest = function () {}; ConstantsTest.MODE = { A: 0, B: 1, C: 2 };
置き換えた後のコード(TypeScript)
interface Mode { // typeでもOK。最近の主流はtypeっぽい? A: 0, B: 1, C: 2 } export default class ConstantsTest { public static MODE: Mode = { A: 0, B: 1, C: 2 }; public static isModeB(mode: Mode[keyof Mode]): boolean { return mode === ConstantsTest.MODE.B; } public static test() { console.log("ConstantsTest.isModeB(ConstantsTest.MODE.A)", ConstantsTest.isModeB(ConstantsTest.MODE.A)); // false console.log("ConstantsTest.isModeB(ConstantsTest.MODE.B)", ConstantsTest.isModeB(ConstantsTest.MODE.B)); // true console.log("ConstantsTest.isModeB(ConstantsTest.MODE.C)", ConstantsTest.isModeB(ConstantsTest.MODE.C)); // false console.log("ConstantsTest.isModeB(0)", ConstantsTest.isModeB(0)); // false console.log("ConstantsTest.isModeB(1)", ConstantsTest.isModeB(1)); // true console.log("ConstantsTest.isModeB(2)", ConstantsTest.isModeB(2)); // false // console.log("ConstantsTest.isModeB(3)", ConstantsTest.isModeB(3)); // compile error } }
この記事で書きたかったこと
interfaceの一つの要素を型で指定する方法がわからなかったけど、解決したので勢いで書いてたりする。
mode: Mode[keyof Mode]
雑感
Partial
とかPick
とかあると便利そうなものが定義されているから、その中にあるもので対応できるかと必死に探したのになー(´・ω・`)
考えてみれば結構シンプルなんだけど、まだTypeScript脳にはなれないようだね。
というか、こういう型が必要なケースって少ないのかな?
でも、やっぱりリテラル型のunionでtype宣言して素直に書き換えた方が良い気がする。最終的にタイトル変えたけど、元々は「【TypeScript】JavaScriptで定数として定義していたものの型を引数で指定するには」だった。移行作業結構面倒だという愚痴のニュアンスが…
追記(2020/02/11)
実体から型を取り出す方法typeof T
を知ったので試してみた。が、少し試してみた結果、厳密には型情報が抜き出せないっぽい様子?
isModeB
の引数はnumberを取ると思われてしまった。
export default class ConstantsTest { public static MODE = { A: 0, B: 1, C: 2 }; public static isModeB(mode: (typeof ConstantsTest.MODE)[keyof typeof ConstantsTest.MODE]): boolean { return mode === ConstantsTest.MODE.B; } public static test() { console.log("ConstantsTest.isModeB(ConstantsTest.MODE.A)", ConstantsTest.isModeB(ConstantsTest.MODE.A)); // false console.log("ConstantsTest.isModeB(ConstantsTest.MODE.B)", ConstantsTest.isModeB(ConstantsTest.MODE.B)); // true console.log("ConstantsTest.isModeB(ConstantsTest.MODE.C)", ConstantsTest.isModeB(ConstantsTest.MODE.C)); // false console.log("ConstantsTest.isModeB(0)", ConstantsTest.isModeB(0)); // false console.log("ConstantsTest.isModeB(1)", ConstantsTest.isModeB(1)); // true console.log("ConstantsTest.isModeB(2)", ConstantsTest.isModeB(2)); // false console.log("ConstantsTest.isModeB(3)", ConstantsTest.isModeB(3)); // compile error にならない... console.log("ConstantsTest.isModeB(\"\")", ConstantsTest.isModeB("")); // compile error } }