tanaka's Programming Memo

プログラミングについてのメモ。

書籍TypeScriptリファレンスのメモ

TypeScriptリファレンス Ver.1.0対応

TypeScriptリファレンス Ver.1.0対応


読んだ際の備忘録。

スコープはJavaScriptと同じ

  • スコープは関数のみ
    • for文などのブロック内のスコープはない

anyの注意

var a: any = "test";
var b: number = a;

以上のコードはビルド時にも実行時にもエラーは発生しない。JavaScriptに変換したコードは以下のとおり。

var a = "test";
var b = a;
console.log(b);

TypeScriptの型が有効なのはコンパイルされるまでであり、JavaScriptに変換されると型情報は消えてしまう。TypeScriptの仕様に沿うようなプログラムが生成されるわけではない。

配列の型

  • 省略すると型は自動判別される
  • TypeScript1.4.1では、型を省略して配列に様々な型のデータが並べてもObject型にはならず、型を|でつないだものになる
  • 複合型は、明示的に型指定をしないと組み込み型の変数に代入できない
  • 型推論がどのように行われるかは、Eclipseであれば変数にマウスカーソルを合わせると表示される
  • 型推論でanyが選択された場合、バグの温床になる可能性がある。tscでは-noImplicitAnyオプションを指定するとエラーになる
    • Eclipseでは、[Eclipse]>[環境設定(Preferences...)]を開いて、[TypeScript]>[Compiler]を選択し、[Raise error on expressions and declarations with an implied 'any' type]にチェックを入れる

オブジェクトへの後でのプロパティの追加は不可

  • プロパティ名間違いを防ぐのには良い仕様

オブジェクトリテラルでプロパティに型指定ができるか?

特殊な値の型

  • 無限大のInfinity、負の無限大の-Infinity、数値以外のNaNは、TypeScriptではnumber型になる
  • 数値のnullは0と解される

関数が利用できるようになるタイミング

JavaScriptの仕様通りだが、以下のとおり。

  • function 関数名()で定義した関数はすぐに利用が可能
  • 無名関数を変数に値渡しする場合は、代入後に利用可能になる

アロー関数式

  • ECMA Script6で導入が検討されている仕様
  • thisの扱いが通常の関数定義と違う

型注釈

  • 関数を代入する予定の変数に、あらかじめ型を設定することができる
var kata: (data: string) => string;

kata = data => "hello"+data;
  • 引数の数は増えるとエラーだが、減るのは構わない
  • Functionで型注釈をしておくと、どのような関数を入れることもできるようになる

引数の省略

  • TypeScriptでは、関数を呼び出す際に引数が不足しているとエラーが発生する
  • 省略可能な引数の場合、引数名の最後に?を記載する
  • 型注釈で引数を1つにした場合でも、1つ目以降の引数名の最後に?をつけておけば、代入することが可能

クラス関連

  • newや利用は、クラス定義をした後にする必要がある
  • クラス内でインスタンス変数にアクセスするには、JavaScriptと同じく、thisが必要
  • privateは、ビルド時の制約であり、any型の変数にクラスのインスタンスを代入すると参照できています。クロージャによる物理的なアクセス制限になっていない
  • staticでクラス変数を定義できる
  • static変数にアクセスするには、static関数とインスタンス関数いずれからもクラス名.static変数名とする

Interface

  • javaのinterfaceと同様のもので、あらかじめメンバを定義するもの
  • JavaScriptには情報は残らない
  • 値の代入はできないし、型推論もしないので型注釈は必須
  • 同じ名前のinterfaceを定義すると、メンバを追加することができる。既存のinterfaceを拡張したい場合に利用する

Module

  • ネームスペースを守るために利用する。classのprivateはコンパイラレベルの隠蔽。クロージャによる物理的な隠蔽はModuleの機能
  • 同じモジュール名で定義を書くと、それらは統合される
  • .で入れ子モジュールを作成できる
  • 定義の実行が終わるまで利用できない
  • Module内の構造を外部に見せないためには、Interfaceで型のみをexportする方法がある
  • importでModuleリストの別名を作成できる

外部モジュール

  • CommonJSやAMD(Asynchronous Module Definition)が定める仕様に従ってモジュールをexportやimportする仕様
  • 1ファイル1モジュールとして、公開しなければ外部に公開されない
  • CommonJSはブラウザ以外での実行ライブラリ
  • AMDはCommonJSのブラウザ版
  • [Eclipse]>[環境設定]>[TypeScript]>[Compiler]の設定に、[Module Code Generation]という設定があり、None、AMD、CommonJSを選択できる

アンビエント宣言

  • jQueryなどの既存のJavaScriptライブラリをTypeScriptで安全に利用できるようにするために、変数や関数の型注釈を記述したもの
  • declareキーワードをつけて、interfaceと同様に宣言する
  • jQueryなどには宣言ソースファイル(Declaration Source File)と呼ばれるアンビエント宣言したファイルが用意されている
  • 拡張子は.d.ts
  • https://github.com/borisyankov/DefinitelyTyped に各種.d.tsファイルが公開されているので探すとよい

総称型(Generic Type)

  • <>で型を実行時に指定できる仕組み
  • null && func()による戻り値の型判定が1.4.1では使えなくなっている模様

リファレンスコメント

/// <reference path="参照パス" />
  • 上記をファイルの先頭行に記述しておくと、ビルド時に参照先もビルドされる
  • --outを指定すると、同一ファイルにビルドされる
  • Eclipseでは、プロジェクトを右クリック>[Properties]>[TypeScript]>[Output file name]を指定しておくと、プロジェクト内のすべてのtsファイルを1つのファイルにまとめる。個別のjsファイルは生成されなくなる

TypeScriptの関数内でのthis

  • 通常の関数は、JavaScriptと同様。コールバックなどではthisはグローバルオブジェクトの参照になる
  • アロー関数式を使うと、一つ外側のthisを保持する。コールバックなどでの利用でthisをとっておくイディオムやbindを利用しなくてよくなる
  • TypeScriptでは、問題がなければアロー関係式を使った方が楽

外部モジュール

  • ファイルを分ける場合、外部モジュールを利用するのが便利
  • [Eclise]>[環境設定(Preferences...)]>[TypeScript]>[Compiler]を選択して、[Module code generation]を[CommonJS]か[AMD]に変更する
  • CommonJSではrequire、AMDではdefineが必要
    • nodeで動かすときは[CommonJS]の設定にすればそのまま動作する
    • ブラウザで動かすときは[AMD]の設定にして、requireJSを組み込む

変数の巻き上げ

  • JavaScriptの仕様
  • 変数などの宣言は、プログラム内のどこに記載しても実行時にはそのスコープの最初に行われる
var val;
(function () {
  val = "abc";
  return;

  var val;
})();

console.log(val);  // undefined
  • 上記は、実行時には以下のように解釈される
var val;
(function () {
  var val;         // ここにくるので、varがローカル変数になる
  val = "abc";
  return;
})();

console.log(var);
  • よって、混乱を避けるためにJavaScriptでは変数はスコープの先頭でまとめて行うのがよい
  • TypeScriptでもこの制約はそのままだが、以下のようなことが起きる
var a,b,c:string;
// aとbはany型になり、エラー。stringはcのみ
  • すべてのローカル変数を型注釈つきで宣言するのはスクリプトの簡易さを損なうので、無理のない範囲で、初めて利用する場所で宣言する方が無理がないとのこと

共通最適型

  • クラスAと、クラスAを継承したクラスBがあり、これらを並べた配列を作成すると、その配列の要素の型は双方の共通型であるAに推定される
  • クラスBのインスタンスを入れていても、クラスBで拡張されたメンバにはアクセスできないので注意(これはポリモーフィズムを利用した配列ではよくある)
  • インターフェースAから継承したBとCがあった時に、BとCの要素を持つ配列を作成すると、Aに推定される。1.0.0の時点では{}に推定されていたようだが、1.4.1では解決している
  • 混乱をさけるため、このような配列は明示的に型を定義するべき
var array:A[] = [b,c];
  • 戻り値のメンバが変更するような場合は1.4.1でもエラー。明示的に戻り値を指定する必要がある
  • 総称型()による型類推も、1.0.0ではエラーだったものが、1.4.1では理油できるようになっている

TypeScriptで利用不可な予約後

  • _i,_this,_super,argumentsは、TypeScriptが内部的に利用するので使わないこと

npmの情報

nodebrew

  • Node.jsはバージョンアップにより互換性がなくなることが多いので注意
  • Node.jsのバージョンを変更する場合などに利用できるのがnodebrewを利用するとよい(MacLinux)
  • windowsだとnvm?

grunt

検証ツール tslint

  • TypeScriptコンパイラよりも厳しくコード規約のチェックを行う

ブラウザで動作するJavaScript用のパッケージマネージャ bower

型定義ファイル.d.ts管理ツール tsd

  • JavaScriptのライブラリをTypeScriptで使えるようにするための型定義ファイルの取得を自動化するツール
  • 便利なので使うべき
  • gruntなどの自動ビルドツールプラグインを入手

NuGet

  • Visual Studioで利用出来るパッケージマネージャ
  • npmやbower,tsdを合わせたようなツール

まるばつ

  • Pieceの定義に空を表すものも追加したい。Piece型の変数なのでPieceで状態を表した方がよさそう
  • p356 innerTextはinnerHTMLの誤り

TODOアプリ

インストール

  • AngularJSの公式ページに行って、ZIPファイルをダウンロードして解凍
  • 型定義ファイルを入手するために、tsdをインストール
sudo npm install -g tsd
  • プロジェクトフォルダに移動して、以下でjsonを作成
tsd init
  • AngularJSの型定義を入手するため、以下を実行
tsd query angular*
  • 表示された中からangularjs/angular.d.tsが目的のもの。以下で入手する
tsd query angularjs/angular --save --resolve --action install
tsd query angularjs/angular-mocks --save --resolve --action install
  • tsd.jsonのinstalled欄にインストールされた結果が並ぶ
  • 以上で完了。別の環境で型定義ファイルを入手するには、tsd.jsonのみを用意して、tsd reinstall --overwrite --save とする
  • bootstrapを http://getbootstrap.com/ からダウンロード

実装

配布している書籍のサンプルファイルから抜粋して解説しており、自分の手で組み立てていきながら理解することができない。さして必要性もなかったので読み飛ばした。

次のenchant.jsも同様。