Help us understand the problem. What is going on with this article?

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

More than 3 years have 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. ただ何故かクラス定数は簡単に定義できない。 

ConquestArrow
ノンプログラマです。
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした