AngularJSのDirectiveをTypeScriptでClass化する方法を理解しながら覚える

# AngularJSのDirectiveをTypeScriptでClass化する方法を理解しながら覚える

今お世話になっているところで、AngularJSのDirectiveをTypeScriptでClass化してみようという宿題を出されたのですが、そのdirectiveがコード量多めで、太っているので、
AngularJSとTypeScript幼稚園生の僕にはちょっと難しいので、何かやせているのないかな、
と思って探していました。
んで
このDirectiveをTSでClass化してみることにしました。
みなさんもやってみてください

```ts


app.directive('MoritaDirective', ()=>{
  return {
    restrict: 'E',
    template: '<div>' +
                '<input type="text" ng-model="message">'+
                '<button ng-click="clear($event)">Clear</button>'+
                '<p>ふぁふぁふぁああふぁ{{ message }}</p>' +
              '</div>',
    link: (scope:any,element:ng.IAugumentedJQuery,attrs: ng.IAttributes)=>{
      scope.clear = ($event) =>{
        scope.message = '';
      };
    }
  }
});
```

まずは何も見ないでできるところまで予想でやってみる。

エラーなんか知らない。
こうじゃねーの？みたいなイメージで。
すぐ答え見て写経しても意味ないですしね。

で、幼稚園生が出した答えがこれです。

```ts


class MoritaDirective {
  restrict: string;
  template: Function;
  constructor(public scope, public element, public attrs){}
  template(){
    return '<div>'+
                '<input type="text" ng-model="message">'+
                '<button ng-click="clear($event)">Clear</button>'+
                '<p>ふぁふぁふぁああふぁ{{ message }}</p>' +
              '</div>'
  }
  clear(){
    return this.massage = '';
  }
  link(){
    return this.clear();
  }
}
app.directive('MoritaDirective', new MoritaDirective());
```

絶対違う。
これでエラーが出ないわけがない。。
さぁどこが間違っているのでしょうか楽しみです


みなさんはどうでしたか？
答えはこちらみたいでした。

```ts

module MoritaModule{//module!!
  export class MoritaDirective {
      constructor(){//controllerの場合はここにサービス入れてたのに違うんだな。。
        return this.CreateDirective(); //コンストラクタ内で関数を返す。
      }
      private CreateDirective():any {//返すメンバメソッドを定義
        return {//オブジェクトとして返すのは一緒か。。
          restrict : 'E',
          template: '<div>'+
                      '<input type="text" ng-model="message">'+
                      '<button ng-click="clear($event)">Clear</button>'+
                      '<p>ふぁふぁふぁああふぁ<em>{{prefix}}</em> - {{ message }}</p>' +
                    '</div>',
          scope: {
            prefix: '@'//独自スコープ//答えはこうなっていたけど問題に属性設定されていないから多分いらない。template内のも使いたい人はどうぞ的な奴だと思う
          },
          link : (scope,element:ng.IAugumentedJQuery,attrs: ng.IAttributes)=>{
            scope.clear = ($event) =>{
              scope.message = '';
            };
          }
        }
      }
  }
}
var app = angualr.module('app',[]);
app.directive('MoritaDirective', ()=> new MoritaModule.MoritaDirective());//newをリターンした無名関数を引数にする

```

CreateDirective()ないに全部書いちゃってこれだと可読性が悪いみたいです。またinterfaceも使った方がいいみたい
↓
↓で、こちらがさらに今のを発展させたもの

```ts


module MoritaModule {
  export interface IDirectiveScope extends ng.IScope{//型ファイルから継承 //link{}内で扱う変数はここ
    message : string;//独自で定義して使うメンバはinterfaceで型注釈しておく
    clear: Function;
  }
  export class MoritaDirective implements ng.IDirective {//returnするKeyを型注釈 //独自のはinterfaceで定義してDirectiveClassに読み込むのか。
    public restrict : string;//Directive、return内のだな。。
    public replace : boolean;//Directive、return内のだな。。
    public template: string;//Directive、return内のだな。。
    public scope: any;//Directive、return内のだな。。//scopeはanyなんだね
    public link : (scope : ng.IScope, element:ng.IAugumentedJQuery, attrs: ng.IAttributes) => void;//link関数をここで型注釈//返り値voidなんだね。
    constructor(){
      this.init()//初期化
    }
    public static Factory(): ng.IDirectiveFactory{//静的なメンバとして外から呼べるように登録
      var directive = ()=> {//templ側でdirctiveが現れる度に毎回呼ばれるようになっている。。
        return new MoritaDirective();//インスタンスを生成する関数を代入
      }
    }
    private init(){//元々のAngularDirective内のkeyはここで定義//
      this.restrict = 'E';
      this.replace = true;
      this.scope = {
        prefix : '@'
      };
      this.link = (scope: IDirectiveScope, element:ng.IAugumentedJQuery, attrs: ng.IAttributes) => {
        scope.clear = ($event) => {//リンク内で毎回呼ばれる関数の定義
          scope.message = '';
        };
      };
      this.template: '<div>'+
                  '<input type="text" ng-model="message">'+
                  '<button ng-click="clear($event)">Clear</button>'+
                  '<p>ふぁふぁふぁああふぁ<em>{{prefix}}</em> - {{ message }}</p>' +
                '</div>';
    }
  }
}
var app = angular.module('app', []);
app.directive('MoritaDirective', MoritaModule.MoritaDirective.Factory());//インスタンスを返す関数を定義しているからか。。
```



もとの僕の予想して書いたファイル見てくださいよ。。
ひどいな。
こんなファイルもしティッシュだったら鼻かんで捨てるわ。

でもおかげで勉強になりました。。

## DirectiveのClassの仕方。まとめると、

**①module内**
**②Directiveのlink内でscopeとして使うつもりの変数をinterfaceで型注釈**
**③class定義。implementsはng.IDirectiveを(型定義ファイル)**
**③link内のデフォkeyはconstructor記述より前で型注釈、linkは無名関数として、引数も型定義ファイルから。void返すように**
---ようやくconstructor内。。
**④this.初期関数を実行する記述**
**⑤staticでFactory関数として自身のインスタンスを返す関数を定義**
**⑥初期関数を定義（デフォのdirectiveのkey）**
**⑦Directive()で呼び出す際はfactory関数を実行した形で。**


①も
②い(interface)
③く(class)
④ち(注釈)
⑤こ(constructorで初期実行)
⑥ふぁ(ご自身を返すFactory関数)
⑦しょ(初期関数)

## もいくちこふぁしょ！！！

DirectiveをClassで書くさいはいろいろな書き方があると思うのでこれが唯一の正解だとは
思いませんが一つの書き方なんですね。


ありがとうございました。

[controller と directive を TypeScript のクラスとして定義する方法 – AngularJS + TypeScript ＃1](http://tech.recruit-mp.co.jp/front-end/writing-ng-controllers-directives-as-ts-classes/)