銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

TypeScriptでスタティックコンストラクタ(のようなもの)を記述する

f:id:takamints:20191215081904p:plain

TypeScriptでスタティックコンストラクタを書く方法の小ネタです。

C#では普通にスタティックコンストラクタを記述できますが、TypeScriptでは書けないようです。

先日「あったらいいな」という状況がありましたので、それっぽい記述を探ってみました。ちょっと無理やりなんですけどね。

実践TypeScript ~  BFFとNext.js&Nuxt.jsの型定義~
吉井 健文
マイナビ出版 (2019-06-26)
売り上げランキング: 14,316
目次

スタティックコンストラクタ?

スタティックコンストラクタとは、主にクラスのスタティックフィールドを初期化するためのもので、最初のインスタンスが生成される前に一度だけ動いてほしいクラスメソッド(みたいなもの)です。

複数のスタティックフィールドを同時に初期化したい場合や、元情報を加工して実行時に使用する情報を作成するといった場合に有用です。

スタティックフィールドを即時実行関数で初期化する

スタティックコンストラクタがなくても、スタティックフィールドは普通に個別に初期化できます。 さらにこの時、以下のように無名関数を即時実行してその戻り値で初期化するのも可能です。

class MyClass {
    static foo:string = (()=> {
        return "foo";
    })();
}

スタティックコンストラクタみたいな記述

無名関数の即時実行を利用すれば、TypeScriptでスタティックコンストラクタ(のようなもの)を以下のように書けます。

class MyClass {

    static foo:string = "foo";

    /**
     * スタティックコンストラクタ(のようなダミーのフィールド)。
     */
    static ctor = (()=>{
        MyClass.foo = "bar";
    })();
}

static ctor というダミーのスタティックフィールドを定義して、即時実行した無名関数の戻り値で初期化しています(ここでは無名関数が何も返していないので結果的には null になります)。

ダミーの名前は ctor である必要はありませんが、本来のインスタンスのコンストラクタとかぶりますから constructor にはできません。

注意すべき点

スタティックフィールドが上から初期化されるということには少し注意が必要です。

以下のように、スタティックコンストラクタよりも下でスタティックフィールドを宣言し、かつ初期化していると意図した動作になりません。コンパイルエラーが出ないので厄介です。

class MyClass {
    /**
     * スタティックコンストラクタ(のようなダミーのフィールド)。
     */
    static ctor = (()=>{
        MyClass.foo = "bar";
    })();

    static foo:string = "foo";
}

初期化していなければ問題はありませんが、ややこしいのでスタティックフィールドはクラス宣言の上のほうで宣言しておいたほうがよさそうですね。

あと、確実にユニットテストを記述するのも有効です。