11
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-05-28

ここ数日、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脳が蘇ってくる感じがして、積極的にリファクタしたい衝動にかられてええ感じです。

以上。

11
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?