Alloy + Typescript でModelを作成する


#概要
AlloyのModelをTypescriptのClassの形に書き直しました。

#ポイント
+ config.columnsをデータ型として使用する。
+ exports.definitionにModelの定義オブジェクトを渡せるようにする。
+ インターフェースを使ってModelの定義方法をチェックする。

##javascriptのModel
以下のModelを元にTypescriptへの書き直しを行います。

```js:Todo.js
exports.definition = {
  config: {
    columns: {
      "task": "text",
      "limitTime": "text",
      "done": "integer"
    },
    adapter: {
      type: "sql",
      collection_name: "Todo"
    }
  },
  extendModel: function (Model) {
    _.extend(Model.prototype, {
      // extended functions and properties go here
    });

    return Model;
  },
  extendCollection: function (Collection) {
    _.extend(Collection.prototype, {
      // extended functions and properties go here
    });

    return Collection;
  }
};
```

##TypescriptのModel
以下の形になりました。

```typescript:Todo.ts
/// <reference path="IExportableModel.d.ts"/>
module models {
    export class Todo extends Backbone.Model implements IExportableModel {
        public config = Todo.config;
        public exportsDefinition = Todo.exportsDefinition
        static config = {
            columns: { 
                "task": "text",
                "limitTime": "numeric",
                "done": "text"
            },
            adapter: {
                type: "sql",
                collection_name: "Todo"
            }
        };
        static exportsDefinition = {
            config: Todo.config,
            extendModel: function(Model: Backbone.Model) {
                _.extend(Model.prototype, Todo.prototype);
                return Model;
            },
            extendCollection: function(Collection: Backbone.Collection) {
                _.extend(Collection.prototype, {
                    // extended functions and properties go here
                });
                return Collection;
            }
        };
        
        constructor(attributes?: any, options?: any) { 
            super(attributes, options);
        }

        public toJSON(options?: any): typeof Todo.config.columns {
            return super.toJSON(options);
        }
    }
}

declare var exports: { definition: any };
exports.definition = models.Todo.exportsDefinition;
```

#詳細
##config.columnsをデータ型として使用する
Typescriptの型推論はオブジェクトリテラルの内部構造もちゃんとデータ型として推論してくれます。
この機能を利用して、toJSONメソッド戻り値のデータ型を設定したオーバーライドメソッドを作成します。

```typescript:Todo.ts
    public toJSON(options?: any): typeof Todo.config.columns {
        return super.toJSON(options);
    }
```
これで、toJSONメソッドの戻り値のオブジェクトからフィールド名が入力補完できるようになります。

##exports.definitionにModelの定義オブジェクトを渡せるようにする
static変数 exportsDefinition を定義し、exports.definition に渡します。

```typescript:Todo.ts
declare var exports: { definition: any };
exports.definition = models.Todo.exportsDefinition;
```

クラスに定義したメソッドはprototypeプロパティに格納されるので、exportsDefinitionのexportModelの定義を以下のようにすることで、クラスのメソッドをexportsDefinitionに含めることができます。

```typescript:Todo.ts
extendModel: function(Model: Backbone.Model) {
    _.extend(Model.prototype, Todo.prototype);
    return Model;
}
```

##インターフェースを使ってModelの定義方法をチェックする
他のModelクラスを作成するときにも同様の方法でexportsDefinitionが定義されることを保証するために、インターフェースを作成します。

```typescript:IExportableModel.ts
interface IExportableModel {
    config: {
        columns: any;
        adapter: {
            type: any;
            collection_name: any
        }
    };
    
    exportsDefinition: {
        config: typeof config;
        extendModel: (Model: Backbone.Model) => Backbone.Model;
        extendCollection: (Collection: Backbone.Collection) => Backbone.Collection;
    };
}
```

#追記
誤解があると申し訳ないので追記です。
私はTitanium + Alloy も TypeScript も先月初めて触った初心者です。
新しい環境と言語で試行錯誤しながらやってみたことを綴っています。
なるべく有用な情報を共有したいと思ってはいますが、ちょっとした間違いから根本的に間違っていることまで色々間違いがあるかもしれません。どうぞご容赦ください。