[JS | TypeScript] Backbone.Collectionのコンストラクターでコンパイルエラーが起きたので

2014/04/9

こんにちは。きんくまです。

おとといBackboneのメモ記事書いたのだけど、TypeScriptに移したらうまくいかなかったので、またまたメモです。

具体的にいうと、Collectionのmodelプロパティの設定についてです。

こんなコードがあったとします。

module sample{
    export class Product extends Backbone.Model{
        name:string;
        price:number;
        defaults(){
            return {
                name:"名無しの製品"
                ,price:0
            }
        }

        initialize(){
            var defaults:any = this.defaults;
            this.name = this.get('name') || defaults.name;
            this.price = parseInt(this.get('price')) || defaults.price;
        }
    }

    export class ProductsCollection extends Backbone.Collection{
        filePath:string = "images/xxxx.png";
        model = Product; //ココの位置

        constructor(options?:any){
            super(options);
        }
    }
}
$(()=>{
    var products = new sample.ProductsCollection([
        {
            name:"炊飯器"
            ,price:8000
        }
        ,{
            name:"掃除機"
            ,price:10000
        }
    ]);
    var results = products.where({name:"炊飯器"});
    console.log(results[0]);
});

これをやるとProductsCollectionのところがうまく機能しませんでした。TypeScriptのバージョンは1.0.0.0です。

理由は吐き出されたjsをみるとわかるのだけど、コンストラクターのsuperが呼ばれたあとにmodelのプロパティを設定しているからでした。

はきだされたjsを一部抜粋

    var ProductsCollection = (function (_super) {
        __extends(ProductsCollection, _super);
        function ProductsCollection(options) {
            _super.call(this, options);
            this.filePath = "images/xxxx.png";
            this.model = Product;
        }
        return ProductsCollection;
    })(Backbone.Collection);

これでもうまくいくためには、Collectionをnewするときに、引数にデータをいれないで、あとから設定するという方法があります。前の記事はfetchであとからデータをいれたので、大丈夫だった。

だけど、もしModelとCollectionを入れ子にしてある場合はコンストラクターにデータが入った状態で、連鎖していくからこの状態だとマズイです。

なので、コンストラクターの前に入れておけば良いんじゃない?と思ってこのコードを書くとコンパイルエラーが出ます。

    export class ProductsCollection extends Backbone.Collection{
        filePath:string = "images/xxxx.png"; //注1

        constructor(models?:any){
            this.model = Product; //ココ!
            super(models);
        }
    }

エラーの内容はsuperはコンストラクターで一番最初に呼ばれないとイクない!というもの。

error TS2104: A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.

ちなみにこのエラーは何故か、上のソースの//注1の部分の = 以下を削除すると解除されます。つまりインスタンスプロパティに代入せず宣言だけならオッケー。
でも、代入したいし。

解決策

で、いろいろとネットを検索したりしたのだけど、いい解決策がなくて困ってたところでもう一度Backbone.jsのリファレンスを見たところで解決しました。(実際はDashというアプリで見てます。なんか今みたら2000円もしてるけど、前って500円くらいじゃなかったけ?と思ってレシート検索したら、1年前の正月に450円で買ってた)

やっぱ公式リファレンスって大事ですな。
>> constructor / initialize

いろいろ書いたくせに、第二引数に入れるだけで良かったという、、orz すみませんすみません。

    export class ProductsCollection extends Backbone.Collection{
        filePath:string = "images/xxxx.png";

        constructor(models?:any){
            super(models, {
                model:Product
            });
        }
    }

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る