5
6

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/ES7で継承不可なクラス

Last updated at Posted at 2015-09-30

ガチガチに固めた、静的な言語のようなクラスをJavaScript(TypeScript+ES6+ES7)で作ってみるシリーズ。

継承不可なクラス

「継承しないといけないクラス」は抽象クラスとしてTypeScript1.6から使えるようになった。が、逆の「継承してはいけないクラス」を定義することができない。

継承されるとまずいクラスがある場合、運用でカバーするしかないが、人間やるなと言われるとやりたくなるもので、運用でなんとかする方法論はだいたいうまくいかない。

フリじゃ無いと言われてもさぁ
/**
* いいか?おまえら。絶対継承するなよ?継承するなよ?
*/
class DontInherit{}

/**
* 「絶対○○するな」=「やれ」ということだな!
*/
class Oyakusoku extends DontInherit{}

/**
 * やるなっていっただろー!?
 */
var ostrich = new Oyakusoku();
console.log(ostrich instanceof DontInherit);	//true

@final decorator

Javaのfinal classやC#のsealed classはそのような継承不可なクラスを定義するものだ。そこで@finalというデコレータをつくってみた。このデコレータを使うとクラスを継承しようとするとランタイムエラーが発生する。

継承できない
@final class DontInherit{}
class Oyakusoku extends DontInherit{}

var ostrich = new Oyakusoku();	//runtime error! : A class "Oyakusoku" cannot inherit from @final class "DontInherit".

仕組み

仕組みは簡単で、コンストラクタ内の処理で基底クラス(のコンストラクタ関数)名とthisオブジェクトのクラス(のコンストラクタ関数)名を比較して違っていたらエラーにするだけ。

@finalの仕組み
const base = target;	//targetは基底クラスのコンストラクタ

//中略

//thisのprototype経由でコンストラクタ名を取得
const thisname = Object.getPrototypeOf(this).constructor.name;

//名前が違っていたらエラーをthrow
if(thisname!==base.name){
	throw Error(`A class "${thisname}" cannot inherit from @final class "${base.name}".`);
}

ES6(ES2015)から導入されたクラスだが、直接クラス名を取得する方法は無い.nameプロパティで仕様では取得できるが、多くの環境で非対応。ただし、ES6のクラスはシンタックスシュガーでしかないので、コンストラクタの関数名prototype.constructor.nameを取得することでクラス名を得る事ができる。

制限

名前で比較するので基底クラスに名前が無いと機能しない。もっとも、匿名クラスにデコレータはつけられない様子。

@final	//error!: Decorators are not valid here
var AnonymousClass = class {}

なお、残念ながらbabelでは今回のコードは動かない。

コード

githubに今回作った@finalデコレータを公開している

5
6
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
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?