Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
13
Help us understand the problem. What is going on with this article?

More than 5 years have passed since last update.

@dayoshix

TypeScriptでstaticなメンバを持つinterfaceみたいなものを実現する方法

ここ数日、TypeScript+Angularの書き味を試しているのですが、staticなメンバを持つinterfaceを作ったろと下記のような感じで書いてみました。

interface Component {
    static name: string;
}

すると、staticキーワードに対してこんなエラーメッセージが。

Property or signature expected.

(確認したTypeScrptバージョンはv1.5-betaです)

対応していないんだろうなとは思いましたが諦めきれずにぐぐってみると、stackoverflowの2年前のスレッドでstaticなメンバを持つinterfaceみたいなものを実現する方法が紹介されていました。

How to define static property in TypeScript interface

この回答

方法としてはinstanceメンバを定義したinterfaceと、staticメンバとして扱うinstanceメンバを定義したinterfaceを作り、それぞれを型チェックされる側とする側で使い分ける、といった感じです。

実際にコードを書いてみるとこんな感じになります。

コードの確認はTypeScript公式サイトでWebブラウザでリアルタイムに確認できて便利です。
参考までに。
http://www.typescriptlang.org/Playground

// instanceメンバを定義するinterface
// 型チェックされる側のclassがimplementsする
interface Component {
    getMessage: () => string;
}

// static扱いにしたいメンバを定義するinterface
interface ComponentStatic {
    // #!! ポイント !!#
    // コンストラクタ関数の型を定義する
    // 型は型チェックされる側のinterface
    new (): Component;
    // instanceメンバだが型チェックされる側ではstaticなメンバとして定義
    name: string;
}

class Util {
    // 型をチェックする側のメソッド
    public static printNames(...components: ComponentStatic[]) {
        let names = components.map<string>((component) => component.name).join(',');
        let fooMsg = new Foo().getMessage();
        let barMsg = new Bar().getMessage();
        document.body.innerHTML = [
            `<p>${names}</p>`,
            `<p>${fooMsg}</p>`,
            `<p>${barMsg}</p>`].join('');
    }
}

// 型チェックされる側のクラス定義
class Foo implements Component {
    // #!! ポイント !!#
    // ComponentStaticのメンバを定義しなくてもこのクラス自体にはエラーは発生しない
    // 但し、Util#printNamesの呼び出しでエラーが発生する
    public static name = 'Foo';

    public getMessage() {
        return `hello ${Foo.name}!!!!`;
    }
}

class Bar implements Component {
    public static name = 'Bar';

    public getMessage() {
        return `hi ${Bar.name}????`;
    }
}

// Foo、Barにstaticなnameがされていないとここでエラーが発生
Util.printNames(Foo, Bar);

できったっぽい。(・∀・)

所感

トリッキーな方法ですがinterfaceを使って実装classに型チェックする側の観点に限定されますがstaticなメンバの定義を義務付ける事が出来ました。

TypeScriptの構造的な型付けという特徴と、コンストラクタ関数のインスタンスも型指定できるということを知る良いきっかけにもなりました。

ですがこの方法は、、

型チェックされる側の実装クラスでstaticなinterfaceの実装漏れ、誤りがあってもエラーが発生せず、型チェックする側を利用するタイミングでしかエラーが発生しないのがコードを書いていて直感的ではないないなぁと感じました。

実装コードもややトリッキーに感じますし、チーム開発で使う場合はなにかしらの説明が必要かと思います。

ちなみに私はもともとJava屋だったのですが、これを調べてる時にそういやJavaのinterfaceもstaticなメソッドとか定義できなかったよなぁとか思っていたらJava8で出来るようになったんですねー。

というこでTypeScript書いていると眠っていたJava脳が蘇ってくる感じがして、積極的にリファクタしたい衝動にかられてええ感じです。

以上。

13
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
13
Help us understand the problem. What is going on with this article?