TypeScriptの主要なゴールは2つです。
- JavaScriptにオプショナルな型システムを提供します
- 将来のJavaScriptで計画されている機能を現在のJavaScriptエンジンに提供します
これらのゴールへの欲求は以下に述べる理由によって動機づけられています。
「JavaScriptに型を追加する理由は?」と不思議に思うかもしれません。
型は、コードの品質と理解容易性を高めることが実証されています。大規模なチーム(Google、Microsoft、Facebook)は、常に、この結論に至っています。具体的には:
- 型は、リファクタリングを行う際の開発速度を高めます。コンパイルの時点でエラーを検出する方が、ランタイムでの実行時にエラーが発生するよりも優れています
- 型は、完璧なドキュメントです。関数のシグネチャは定理であり、関数の本体は証明です
しかし、型には過剰に儀式的な面があります。TypeScriptは、次に述べるように、型を導入する障壁を可能な限り低くしています。
TypeScriptは、JavaScriptコードのコンパイル時の型安全性を提供します。その名前はこれを表しています。素晴らしい点は、型の使用が完全に任意(オプション)であることです。あなたのJavaScriptコード.js
ファイルを.ts
ファイルに名前を変更したとしても、TypeScriptは元のJavaScriptファイルと同じ有効な.js
を返します。TypeScriptは意図的かつ厳密なJavaScriptのスーパーセットであり、任意の型チェック機構を持ったプログラミング言語です。
TypeScriptは、生産性へのコストを最小限に抑えて型の安全性を提供するために、可能な限り、型推論を行います。たとえば、次の例では、TypeScriptはfooの型がnumber
であると推測し、2行目のコードにエラーを表示します。
var foo = 123;
foo = '456'; // Error: cannot assign `string` to `number`
// Is foo a number or a string?
型推論を必要とする大きな理由があります。この例のようなコードを書いた場合、残りのコードにおいてfoo
がnumber
であるかstring
であるかを確定できません。この問題は、大規模なコードベースで頻繁に勃発します。後で型推論のルールの詳細を説明します。
これまで述べたように、TypeScriptは安全に行える場合は可能な限り型推論を行います。しかしながら、アノテーションを記述することによって、以下のメリットが得られます:
- コンパイラを助けるだけでなく、より、重要なことに、あなたの書いたコードを次に読まなくてはならない開発者にとってのドキュメントの一助になります。(将来のあなたかもしれない!)
- コンパイラがどのように理解するかを強制します。つまり、コードに対するあなたの理解が、コンパイラのアルゴリズムによる分析と一致します。
TypeScriptは、他の任意な型付き言語(ActionScriptやF#など)で一般的な、末尾型アノテーション(Postfix type annotation)を使用します。
var foo: number = 123;
何か間違っていたら、コンパイラはエラーを出します:
var foo: number = '123'; // Error: cannot assign a `string` to a `number`
TypeScriptでサポートされている型アノテーションの詳細については、今後の章で説明します。
いくつかの言語(特に型付き言語と呼ばれるもの)において、静的な型付けは、過剰に儀式的なコードになってしまいます。なぜならば、コードが正常に動作することを確信できていたとしても、構文ルールがそこら中に同じコードをコピー&ペーストすることを強制するからです。C#のautomapper for C#のようなものが必須である理由です。JavaScript開発者にとっての認知的な負荷を最小限に抑えることを簡単にするため、TypeScriptにおける型は構造的(structural)になっています。これが意味することは、ダックタイピング(duck typing)が、ファーストクラスの言語構造であるということです。次の例を考えてみましょう。関数iTakePoint2D
は、期待する全てのメンバ(例では、x
と y
)を含む構造であれば、何でも受け入れます:
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
var point2D: Point2D = { x: 0, y: 10 }
var point3D: Point3D = { x: 0, y: 10, z: 20 }
function iTakePoint2D(point: Point2D) { /* do something */ }
iTakePoint2D(point2D); // exact match okay
iTakePoint2D(point3D); // extra information okay
iTakePoint2D({ x: 0 }); // Error: missing information `y`
JavaScriptのコードをTypeScriptに移行することを簡単にするため、デフォルトでは、コンパイルエラーがあったとしても、TypeScriptは有効なJavaScriptを出力します。例:
var foo = 123;
foo = '456'; // Error: cannot assign a `string` to a `number`
次のjsを出力します:
var foo = 123;
foo = '456';
これにより、JavaScriptコードを段階的にTypeScriptに移行することができます。これは他の言語のコンパイラの動作とは全く異なっており、そして、TypeScriptに移行する理由の1つです。
TypeScriptの設計における大きなゴールは、TypeScriptで既存のJavaScriptライブラリを安全かつ簡単に利用できることです。TypeScriptはこれを型宣言(declaration)で行います。TypeScriptにおいて、型宣言にどれくらいの労力をかけるかは調整可能です。より多くの労力をかければ、より多くの型安全性とIDEによるコード補完(code intelligence)が獲得できます。有名なJavaScriptライブラリの型定義は、DefinitelyTyped communityによって既に作成されているため、
- 定義ファイルが既に存在します。
- あるいは、最低でも、きちんとレビューされた多くのTypeScript宣言のテンプレートが既に利用可能です。
独自の型宣言ファイルを作成する簡単な例として、jqueryの簡単な例を考えてみましょう。TypeScriptは、デフォルト設定において(望ましいJavaScriptコードのように)、変数を使う前に宣言する(つまり、どこかでvar
を使う)ことを期待しています。
$('.awesome').show(); // Error: cannot find name `$`
簡単な修正方法は、変数$
が実際に存在することをTypeScriptに伝えることです。
declare var $: any;
$('.awesome').show(); // Okay!
必要に応じて、より多くの詳細を記述し、あなたをプログラミングの誤りから守ることができます。
declare var $: {
(selector:string): any;
};
$('.awesome').show(); // Okay!
$(123).show(); // Error: selector needs to be a string
TypeScriptの詳細を理解した後で、既存のJavaScriptコードのTypeScript定義に関して詳しく説明します(interface
やany
など)。
TypeScriptは、現在のJavaScriptエンジン(ES5のみをサポートする)に対して、ES6以降で計画されている多くの機能を提供します。TypeScriptチームは積極的に機能を追加しています。機能の一覧は時間とともに増えていく予定です。これらについては独自の章で説明します。ただのサンプルとしてクラスの例を提示しておきます:
class Point {
constructor(public x: number, public y: number) {
}
add(point: Point) {
return new Point(this.x + point.x, this.y + point.y);
}
}
var p1 = new Point(0, 10);
var p2 = new Point(10, 20);
var p3 = p1.add(p2); // { x: 10, y: 30 }
それと、かわいい太っちょのアロー関数も。:
var inc = x => x+1;
この章では、TypeScriptを使う動機とTypeScriptの設計ゴールを説明しました。これで、TypeScriptの隅々まで詳細を追うことができます。
[](Interfaces are open ended) [](Type Inferernce rules) [](Cover all the annotations) [](Cover all ambients : also that there are no runtime enforcement) [](.ts vs. .d.ts)