souki-paranoiastのブログ

地方都市でプログラマーをやっている人のブログ。技術ネタ以外も少し書く。メインの言語はJava。https://paranoiastudio-japan.jimdo.com/ に所属

【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
    }
}