この記事は、Angularをテーマとした日本初のカンファレンス 「ng-japan」のイベントレポート（第4回目）です。

はじめに

昨年秋に、Angular 2はAtScriptというaltJSで開発するといったアナウンスがありました。しかし、今年3/5に急遽、Angular 2はTypeScriptで開発するという変更がなされました。このニュースはGoogle社とMicrosoft社が手を結んだということでも大きなニュースになり、今年一番の出来事かもしれません。

そのTypeScriptとカレントバージョンであるAngular 1.3を利用した開発ポイントを、株式会社トップゲートのエンジニアであり、TypeScriptマスターでもある@vvakame氏に講演していただきました。

TypeScript+Angular 1.3 – vvakame

AtScriptからTypeScriptに移行される旨がアナウンスされたため、TypeScript自体の話を少しと、現行のAngular 1.3とTypeScriptを組み合わせて開発する方法についてお話します。

「AtScriptの近況と将来」の話をしようと思いましたが、3月頭に必要なくなったようなのでタイトルを変えました。「TypeScript+Angular 1.3」というタイトルでお話させていただきます。

Angularを取り巻く開発言語

ECMAScriptとは

ECMAScriptに関して整理します。

JavaScriptの元となる仕様のこと

DOMの仕様は入っていない

最近のブラウザはECMAScript 5をサポート

そろそろ6の仕様が確定（現在RC2

AtScriptとは

AtScriptとは何だったのかを振り返ってみます。

AtScript=ES6+A (A=Annotiosion, AnnotationはES6に含まれない)

Super set of TypeScript

AngularチームがAngular 2を開発するために策定したTypeScriptより、優れているaltJSということでした。

TypeScriptとは

では、TypeScriptの特徴はどういうものかを整理します。

TypeScriptはJavaScriptを拡張した言語

静的型付け

ECMAScript6規格の文法を取り込み中

読みやすい変換後JavaScript

Java, C#とかにやさしい言語仕様

TypeScriptは、Microsoftが出してきたということで当時注目されました。特徴の一つである静的型付けの特徴をまとめます。

静的解析で多くの整合性検証が可能

不整合があった場合、コンパイルエラー

大規模、大人数になるほど有利

Java, C#が有名

通常のJavaScriptでは、バグに関して実際に動かしてみて初めて分かりますが、TypeScriptのような静的型付けを用いると、静的解析でより多くの整合性検査が可能です。なるべくコンパイルした段階で、エラーが出力されるところが良い点の一つです。

例えば次の文はエラーになります。

var foo: number="bar"; 1 var foo: number = "bar" ;

TypeScriptは、ECMAScript 6のスーパーセットになると考えられています。既存の資産を活用したいという要望も当然あります。そうした要望を満たすため、TypeScriptに様々なJavaScriptライブラリの型を定義した型情報を用意する必要があります。例えば、次のようなものがあります。

jQuery

Angular

mocha

etc

DefinitelyTyped

型定義ファイルというものがあります。現在は1,000個以上あります。既存JavaScriptに型を後付けというのはわかりづらいとは思います。

Angularの例を見てみます。

declare var angular: angular.IAngularStatic; // Type definitions for Angular JS 1.3+ // Project: http://angularjs.org // Definitions by: Diego Vilar // Definitions: https://github.com/borisyankov/DefinitelyTyped /// declare var angular: angular.IAngularStatic; // Support for painless dependency injection interface Function { $inject?: string[]; } // Collapse angular into ng import ng = angular; // Support AMD require declare module 'angular' { export = angular; } /////////////////////////////////////////////////////////////////////////////// // ng module (angular.js) /////////////////////////////////////////////////////////////////////////////// declare module angular { // not directly implemented, but ensures that constructed class implements $get interface IServiceProviderClass { new (...args: any[]): IServiceProvider; } interface IServiceProviderFactory { (...args: any[]): IServiceProvider; } // All service providers extend this interface interface IServiceProvider { $get: any; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 declare var angular: angular . IAngularStatic ; // Type definitions for Angular JS 1.3+ // Project: http://angularjs.org // Definitions by: Diego Vilar // Definitions: https://github.com/borisyankov/DefinitelyTyped /// declare var angular: angular . IAngularStatic ; // Support for painless dependency injection interface Function { $ inject ? : string [ ] ; } // Collapse angular into ng import ng = angular ; // Support AMD require declare module 'angular' { export = angular ; } /////////////////////////////////////////////////////////////////////////////// // ng module (angular.js) /////////////////////////////////////////////////////////////////////////////// declare module angular { // not directly implemented, but ensures that constructed class implements $get interface IServiceProviderClass { new ( . . . args : any [ ] ) : IServiceProvider ; } interface IServiceProviderFactory { ( . . . args : any [ ] ) : IServiceProvider ; } // All service providers extend this interface interface IServiceProvider { $ get : any ; }

実際にこれを使ってコードを見てみます。JavaScriptとあまり変わりがないので読みやすいのではないかと思います。

module App { "use strict"; angular.module( "app", ["ngRoute", "app.hello"], ($routeProvider: ng.route.IRouteProvider, $locationProvider: ngILocationProvider)=> { $routeProvider .when("/sample", { templateUrl: "/template/sample.html" }) .otherwise({ templateUrl: "/template/main.html" }); $locationProvider.html5Mode(true); } ) .run(($rootScope: ngIRootScopeService, $routeParams: ng.route.IRouteParamsService)=> { false; }) ; angular.module( "app.hello", [], ()=> { false; } ) .service("sampleService", Service.SampleService) .controller("SampleTestController", Sample.TestController) ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 module App { "use strict" ; angular . module ( "app" , [ "ngRoute" , "app.hello" ] , ( $ routeProvider : ng . route . IRouteProvider , $ locationProvider : ngILocationProvider ) = > { $ routeProvider . when ( "/sample" , { templateUrl : "/template/sample.html" } ) . otherwise ( { templateUrl : "/template/main.html" } ) ; $ locationProvider . html5Mode ( true ) ; } ) . run ( ( $ rootScope : ngIRootScopeService , $ routeParams : ng . route . IRouteParamsService ) = > { false ; } ) ; angular . module ( "app.hello" , [ ] , ( ) = > { false ; } ) . service ( "sampleService" , Service . SampleService ) . controller ( "SampleTestController" , Sample . TestController ) ;

Angular 2とTypeScript

2015年3月5日に、Angular 2はTypeScriptで作ることになるという記事が出てきました。AtScriptからTypeScriptに変えた理由がいくつかあり、AngularチームとTypeScriptチームの調整がうまくいったのではないかと考えられます。

TypeScriptに必要な機能が入る

Angularチームが作りたいのは、AtScriptではなくAngular本体である

TypeScriptのスーパーセットを作るのが困難

TypeScriptのスーパーセットを作るという話でしたが、TypeScript自体の開発スピードがかなり早く、しかもその間にECMAScript 6の仕様も出て、短期間の内にAtScriptを開発するためには、人的にもコスト的にも難しい状況だと考えられます。

話をまとめると、Angularを使うという観点からも、今からTypeScriptを使う必要があると言えます。

TypeScriptのSyntax

TypeScriptの独自Syntaxはあまりなく、JavaScriptとそれほど変わるものではありません。TypeScriptですが、だいたい2日もあれば書けるようになると思われます。

Type Annotations

Type Annotationsを具体的に見てみます。

var str1:string = "string"; var str2:number = "string"; // エラー var str3 = "string"; // 初期化子から型推論されstringを指定したのと等価 str3 = 1; //エラー var b: boolean = true; var n: number = 1; var a: any = true; a = 1; // anyは何でもOK 1 2 3 4 5 6 7 8 9 10 var str1: string = "string" ; var str2: number = "string" ; // エラー var str3 = "string" ; // 初期化子から型推論されstringを指定したのと等価 str3 = 1 ; //エラー var b: boolean = true ; var n: number = 1 ; var a: any = true ; a = 1 ; // anyは何でもOK

Classes

ECMAScript 6からは、クラスの宣言ができるようになりました。TypeScriptの例を見てみます。

class Hoge { name: string; constructor(name: string) { this.name = name; } hello(): string{ return "Hello, " + this.name; } } var obj = new Hoge("world"); window.alert(obj.hello()); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Hoge { name : string ; constructor ( name : string ) { this . name = name ; } hello ( ) : string { return "Hello, " + this . name ; } } var obj = new Hoge ( "world" ) ; window . alert ( obj . hello ( ) ) ;

Interface

TypeScriptで定義したInterfaceは、実行時には消えてしまいます。型だけの定義です。

interface Hoge { str: string; num: number; } var obj: Hoge = { str: "string", num: 1 }; window.alert(obj.str + obj.num); window.alert(obj.hello()); 1 2 3 4 5 6 7 8 9 10 11 12 interface Hoge { str : string ; num : number ; } var obj: Hoge = { str : "string" , num : 1 } ; window . alert ( obj . str + obj . num ) ; window . alert ( obj . hello ( ) ) ;

Allow Functions

Allow Functionsは、最近話題になっています。メリットとしては、functionというキーワードが必要なくなるところです。これはECMAScript 6でも標準化されますので、TypeScriptを通して今のうちから慣れるのもよいかと思います。

var hello = (word: string) => console.log("Hello, " + word); hello("TypeScript"); // 返り値の型を明示する var hello2 = (word: string): void => console.log("Hello, " + word); // 参考：今まで通りの書き方 1 var hello3 = function (word: string) { console.log("Hello, " + word); }; // 参考：今まで通りの書き方 2 function hello4(word: string) { console.log("Hello, " + word); } 1 2 3 4 5 6 7 8 9 var hello = ( word : string ) = > console . log ( "Hello, " + word ) ; hello ( "TypeScript" ) ; // 返り値の型を明示する var hello2 = ( word : string ) : void = > console . log ( "Hello, " + word ) ; // 参考：今まで通りの書き方 1 var hello3 = function ( word : string ) { console . log ( "Hello, " + word ) ; } ; // 参考：今まで通りの書き方 2 function hello4 ( word : string ) { console . log ( "Hello, " + word ) ; }

internal modules

今までのJavaScriptでは、モジュールの定義するというのは存在していませんでした。TypeScriptではモジュールが定義されています。今は過渡期でこうした書き方ですが、ECMAScript 6だと書き方があるので、なくなると思われます。

module app { export class Sample { hello(word = "TypeScript") { return `Hello, ${word}`; } } } var obj = new app.Sample(); console.log(obj.hello("AngularJS")); var app; (function (app) { var Sample = (function () { function Sample() { } Sample.prototype.hello = function (word) { if (word === void 0) { word = "TypeScript"; } return "Hello, " + word; }; return Sample; })(); app.Sample = Sample; })(app || (app = {})); var obj = new app.Sample(); console.log(obj.hello("AngularJS")); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 module app { export class Sample { hello ( word = "TypeScript" ) { return ` Hello , $ { word } ` ; } } } var obj = new app . Sample ( ) ; console . log ( obj . hello ( "AngularJS" ) ) ; var app ; ( function ( app ) { var Sample = ( function ( ) { function Sample ( ) { } Sample . prototype . hello = function ( word ) { if ( word === void 0 ) { word = "TypeScript" ; } return "Hello, " + word ; } ; return Sample ; } ) ( ) ; app . Sample = Sample ; } ) ( app || ( app = { } ) ) ; var obj = new app . Sample ( ) ; console . log ( obj . hello ( "AngularJS" ) ) ;

Generics

Genericsは非常に便利です。

class Container { constructor(public data: T) { } } var a = new Container("str"); var b = new Container(1); a.data.charAt(0); b.data.toExponential(); 1 2 3 4 5 6 7 8 9 class Container { constructor ( public data: T ) { } } var a = new Container ( "str" ) ; var b = new Container ( 1 ) ; a . data . charAt ( 0 ) ; b . data . toExponential ( ) ;

はじめてみよう – Angular-typescript

@vvakameのgithubにあるので是非見ていただき、TypeScriptを始めてもらえたらと思います。

開発する際、利用するツールは次の通りです。

node.js

grunt

bower

TypeScript ** tslint ** typedoc ** dtsm (tsd)

LESS

unit test ** mocha ** power-assert

karma

protractor

その他

Angular 1.3と組み合わせる

あまり考えなくてよく、TypeScriptと重ねることは特別なことはないです。TypeScriptはJavaScriptの延長線上にあり、JavaScriptのベストプラクティスがそのまま利用することができます。

その中で覚えなければならないのは

型の名前

使いたいメソッド（angularのドキュメントを読むより型定義ファイルを見たほうが早い）

使いたいDIオブジェクト名

その中で次のことに注意すれば、問題なく記述することができます。

tsc –noImplicitAny

型注釈を書く

プレゼンテーション資料

今回取り上げたプレゼンテーションの資料は、以下のとおり公開されています。合わせてご覧ください。

セッション動画

当日のセッションはYouTubeで公開されています。是非ご覧ください！