JavaScript
TypeScript
ECMAScript
babel

ES6ではデータのプロパティをクラス直下で定義できない

More than 1 year has passed since last update.

TypeScriptでクラス定数をプロパティとして定義できない件を記事にした。

理由としてはおそらくECMAScript由来の仕様だろうと思い調べてみたところ、 ES6(ES2015)では定数に限らずデータのプロパティをクラスのブロック直下に定義できない ことがわかった。

babelでテスト
class Test{
    prop = 1;   //error! Unexpected token (2:6)
}

ES6でのデータのプロパティの持たせ方

仕様ではクラス直下の本体部分で定義できるのはメソッドのみでデータを保持する変数や定数は定義できない。

ClassBody[Yield] :
    ClassElementList[?Yield]
ClassElementList[Yield] :
    ClassElement[?Yield]
    ClassElementList[?Yield] ClassElement[?Yield]
ClassElement[Yield] :
    MethodDefinition[?Yield]
    static MethodDefinition[?Yield]
    ;

データのクラスプロパティ自体が持てない訳ではなく、メソッドの内部でthis.prop = 1;のように定義するか、クラスのインスタンスに後からプロパティをくっつける事で出来る。

持たせ方
class Test{
    constructor(){
        this.prop = 1;  //ok
    }
}
var a = new Test();
console.log(a.prop);    //1

a.prop2 = "str";
console.log(a.prop2); //str

クラス定数も出来ない事は無い。

クラス定数っぽいもの
class Test{
    constructor(){
    }

    get MAX(){
      return 10000;
    }
}
var a = new Test();
console.log(a.MAX); //10000
a.MAX = 0;  //error! 代入不可

TypeScriptでは

TypeScriptではクラスのデータプロパティをクラスの直下で定義できる。さらに、public/private/protected等のアクセス修飾子でアクセスの制御もできる。

OOPをやるならカプセル化のためにアクセス制御が必要なのでECMAScript側の仕様が固まる前に実装しているのだろう1。まあ、普通。

TypeScript
class Test{
    prop = 1;   //ok
    static prop2 = 3;   //ok
    private prop3 = 1;  //ok
    protected prop4 = 1;    //ok
}
class Test2 extends Test{
    get prop5(){
        return this.prop4;
    }
}
var a = new Test();
console.log(a.prop);    //1
console.log(Test.prop2);    //3
console.log(a.prop3);   //error!
console.log(a.prop4);   //error!
var b = new Test2();
console.log(b.prop4);   //error!
console.log(b.prop5);   //1

Babelでは

experimentalフラグをONにすればいける。ES.nextで仕様検討中のため。

class Test{
    prop = 1;   //ok, experimental on
}

なお、フラグをONにしなくても、値を代入しない定義だけならエラーにならなかった。これがES6の仕様に即しているのかはわからない。

babelでエラーにならないけど合ってる?
class Test{
    prop;
}

以下、愚痴。何が問題なのか。

  • this.propで宣言するのはインデントが一つ深いのでパッと見理解しにくい
    • 同一スコープなんだから、同じインデントにしようよ
  • 他のクラスベースの言語に合わせようよ
    • 使いにくいオリジナリティとか要らないから
  • クラスレベルのスコープの定数が定義しにくい
    • ただでさえスコープ制御が貧弱なんだからもう少しなんとかならなかったの?
    • Number.MAX_SAFE_INTEGERみたいなのを簡単に定義させてほしい
  • アンチパターンとしてクラスプロパティの宣言時に値を入れておきたくないというのはわかる
    • staticなプロパティや定数までできなくしたのはやり過ぎじゃ?
    • そのくせ宣言後のクラスインスタンスにプロパティ生やせちゃうのは…どうにかならなかったん?
  • IDEの補完にむいてなさそう
    • 最近の各IDEの補完は賢いからこれは杞憂に終わるかも
  • ES.nextー!早く来てくれー!

  1. ただ何故かクラス定数は簡単に定義できない。