TypeScript 1.6

JSXサポート

JSXは埋め込み可能なXMLライクな構文です。 これは有効なJavaScriptに変換されることを意図していますが、その変換のセマンティクスは実装固有のものです。

JSXはReactライブラリで人気を博しましたが、その他のアプリケーションでも使われるようになってきました。 TypeScript 1.6は、埋め込み、型チェック、任意でJSXをJavaScriptに直接コンパイルすることをサポートするようになりました。

新しい.tsxファイル拡張子とas演算子

TypeScript 1.6は新しい.tsxファイル拡張子を導入しました。 この拡張子は2つのことを行います。 1つ目はTypeScriptファイル内のJSXを有効にし、2つ目は新しいas演算子をデフォルトのキャスト方法にします。 (JSX式とTypeScriptの接頭辞キャスト演算子の曖昧さを排除します) 例えば、

var x = <any> foo;
// は下記と等価です
var x = foo as any;

Reactの使用

Reactを使用する際にJSXサポートを使用するには、React typingsを使用する必要があります。 これらのtypingsはJSX名前空間を定義し、TypeScriptがReactのJSX式を正しくチェックできるようにします。 例えば、下記のように書くことができます。

/// <reference path="react.d.ts" />

interface Props {
  name: string;
}

class MyComponent extends React.Component<Props, {}> {
  render() {
    return <span>{this.props.foo}</span>
  }
}

<MyComponent name="bar" />; // OK
<MyComponent name={0} />; // error, `name` is not a number

別のJSXフレームワークの使用

JSX要素の名前とプロパティは、JSX名前空間に対して検証されます。 フレームワークにJSX名前空間を定義する方法については、JSXのwikiページを参照してください。

Output generation

TypeScriptには保守(preserve)とreactという2つのJSXモードが付属しています。

  • 保守(preserve)モードは、別の変換ステップで更に使用される出力の一部としてJSX式が保持されます。 さらに、出力ファイルには.jsx拡張子が付きます。
  • reactモードはReact.createElementを出力し、使用する前にJSX変換を行う必要はなく、 出力ファイルに.js拡張子が付きます。

TypeScriptでのJSXの使用についての詳細は、JSXを参照してください。

交差型(Intersection types)

TypeScript 1.6は、論理型の論理補集合である交差型が導入されています。 共用体型(Union Types)A | Bは、Aの型またはBの型のいずれかのエンティティを表し、 一方、交差型(Intersection Types)A & BはAの型とBの型の両方のエンティティを表します。

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U> {};
    for (let id in first) {
        result[id] = first[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            result[id] = second[id];
        }
    }
    return result;
}

var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
type LinkedList<T> = T & { next: LinkedList<T> };

interface Person {
    name: string;
}

var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;
interface A { a: string }
interface B { b: string }
interface C { c: string }

var abc: A & B & C;
abc.a = "hello";
abc.b = "hello";
abc.c = "hello";

詳細については、issue #1256を参照してください。

ローカルの型宣言

ローカルのクラス、インターフェイス、enum、型エイリアスの宣言を、関数宣言内に置けるようになりました。 ローカルでの型はletconstで宣言した変数と同様にブロックスコープされます。 下記はその一例になります。

function f() {
    if (true) {
        interface T { x: number }
        let v: T;
        v.x = 5;
    }
    else {
        interface T { x: string }
        let v: T;
        v.x = "hello";
    }
}

関数の戻り値の型推論は、関数内のローカルで宣言された型である可能性があります。 関数の呼び出し元がそのような型を参照することはできませんが、構造的に一致させることは可能です。 下記はその一例になります。

interface Point {
    x: number;
    y: number;
}

function getPointFactory(x: number, y: number) {
    class P {
        x = x;
        y = y;
    }
    return P;
}

var PointZero = getPointFactory(0, 0);
var PointOne = getPointFactory(1, 1);
var p1 = new PointZero();
var p2 = new PointZero();
var p3 = new PointOne();

クラス式

TypeScript 1.6で、ES6のクラス式のサポートが追加されました。 クラス式では、クラス名が任意に指定されると、クラス式自体のスコープ内にのみ存在することになります。 これは、関数式の任意の名付けに似ています。

クラス式の外にある、クラス式のクラスのインスタンスの型を参照することはできませんが、 構造的に型を一致させることは可能です。

下記はその一例になります。

let Point = class {
    constructor(public x: number, public y: number) { }
    public length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
};
var p = new Point(3, 4);  // pは匿名のクラスの型を持つ
console.log(p.length());

式の拡張

TypeScript 1.6で、任意の式によってコンストラクタ関数を算出してクラスを拡張するサポートが追加されました。 これは、組み込みの型をクラス宣言によって拡張できるようになったことを意味します。

以前はクラスのextendsは、型の参照を指定する必要がありましたが、 このバージョンでは、型引数のリストが後ろに続く任意の式を受け入れるようになりました。

この式の型は、少なくとも1つのコンストラクタ構文を持つ、コンストラクタ関数型でなければいけません。 この構文にはextendsで指定される型の引数の数と同じ数の型引数を持たせる必要があります。

コンストラクタの構文に一致する戻り値の型は、クラスのインスタンスの型が継承する基底の型になります。 これによって実際のクラスと、"クラスのような"式の両方をextendsに指定できるようになりました。

下記に幾つかの例を示します。

// 組み込みの型のextends

class MyArray extends Array<number> { }
class MyError extends Error { }

// 算出された基底クラスのextends

class ThingA {
    getGreeting() { return "Hello from A"; }
}

class ThingB {
    getGreeting() { return "Hello from B"; }
}

interface Greeter {
    getGreeting(): string;
}

interface GreeterConstructor {
    new (): Greeter;
}

function getGreeterBase(): GreeterConstructor {
    return Math.random() >= 0.5 ? ThingA : ThingB;
}

class Test extends getGreeterBase() {
    sayHello() {
        console.log(this.getGreeting());
    }
}

抽象(abstract)クラスと抽象メソッド

TypeScript 1.6では、クラスとそのメソッドのためのabstractキーワードのサポートが追加されました。 抽象クラスは実装されていない(中身のない)メソッドを持つことができ、コンストラクト(new)されることができません。

abstract class Base {
    abstract getThing(): string;
    getOtherThing() { return 'hello'; }
}

let x = new Base(); // エラー,'Base'はabstractです

// abstractにするか、getThingを実装しなければいけません
class Derived1 extends Base { }

class Derived2 extends Base {
    getThing() { return 'hello'; }
    foo() {
        super.getThing();// エラー: superでabstractメンバを実行することはできません
    }
}

var x = new Derived2();       // OK
var y: Base = new Derived2(); // これも OK
y.getThing();                 // OK
y.getOtherThing();            // OK

ジェネリクス型のエイリアス

TypeScript 1.6では、型エイリアスをジェネリクスにすることができます。 下記はその例になります。

type Lazy<T> = T | (() => T);

var s: Lazy<string>;
s = "eager";
s = () => "lazy";

interface Tuple<A, B> {
    a: A;
    b: B;
}

type Pair<T> = Tuple<T, T>;

より厳格なオブジェクトリテラル代入チェック

TypeScript 1.6では、プロパティへのミススペルや過剰な指定を事前に防ぐために、 より厳格なオブジェクトリテラルへの割り当てチェックを強制します。

具体的には、新しいオブジェクトリテラルが変数に代入されたり、空ではない対象の型へ引数として渡されたりする際に、 対象の型に存在しないプロパティが指定されたオブジェクトリテラルはエラーになります。

var x: { foo: number };
x = { foo: 1, baz: 2 };  // エラー、'baz'が過剰なプロパティ

var y: { foo: number, bar?: number };
y = { foo: 1, baz: 2 };  // エラー、'baz'が過剰なプロパティまたは誤記

型には、過剰なプロパティが許可されていることを明示的に示すインデックスのシグネチャを含めることができます。

var x: { foo: number, [x: string]: any };
x = { foo: 1, baz: 2 };  // OK、'baz'はインデックスのシグネチャに一致

ES6ジェネレーター

TypeScript 1.6で、ES6を対象とした際のジェネレーターのサポートが追加されました。

ジェネレーター関数は、関数のように戻り値の型アノテーションを持つことができます。 アノテーションは、関数によって返されるジェネレーターの型を表します。 下記はその一例になります。

function *g(): Iterable<string> {
    for (var i = 0; i < 100; i++) {
        yield ""; // string is assignable to string
    }
    yield * otherStringGenerator(); // otherStringGenerator must be iterable and element type assignable to string
}

型アノテーションのないジェネレーター関数は、型アノテーションを推論することができます。 そのため下記の場合は、型はyield文から推論されます。

function *g() {
    for (var i = 0; i < 100; i++) {
        yield ""; // infer string
    }
    yield * otherStringGenerator(); // infer element type of otherStringGenerator
}

async関数の試験的サポート

TypeScript 1.6では、ES6を対象としたasync関数の実験的なサポートが導入されています。 非同期(async)関数は非同期処理を実行し、通常のプログラム実行をブロックすることなく、その結果を待ち受けることが期待されます。

これは、ES6互換のPromiseの実装を使用して実行され、待機している非同期処理が完了したときに実行を再開するために、 関数本体を互換性のある形式に変換します。

async修飾子が前に付いた関数またはメソッドが、非同期関数になります。 この修飾子は関数本体の変換が必須であり、 awaitキーワードが識別子の代わりに単項式として扱われるべきであることをコンパイラに通知します。

非同期関数は、互換性のあるPromise型を示す戻り値の型アノテーションを提供する必要があります。 戻り値の型推論は、グローバルに定義された互換性のあるPromise型がある場合にのみ使用できます。

var p: Promise<number> = /* ... */;
async function fn(): Promise<number> {
  var i = await p; // pが解決されるまで実行を中断します。iはnumber型を持ちます。
  return 1 + i;
}

var a = async (): Promise<number> => 1 + await p; // 実行を中断します。
var a = async () => 1 + await p; // 実行を中断します。
                                 // --target ES6を使用してコンパイルされた場合、戻り値の型は"Promise<number>"と推論されます。
var fe = async function(): Promise<number> {
  var i = await p; // pが解決されるまで実行を中断します。iはnumber型を持ちます。
  return 1 + i;
}

class C {
  async m(): Promise<number> {
    var i = await p; // pが解決されるまで実行を中断します。iはnumber型を持ちます。
    return 1 + i;
  }

  async get p(): Promise<number> {
    var i = await p; // pが解決されるまで実行を中断します。iはnumber型を持ちます。
    return 1 + i;
  }
}

Nightlyビルド

厳密には言語の変更ではありませんが、nightlyビルドは次のコマンドを使用してインストール可能になりました。

npm install -g typescript@next

モジュール解決ロジックの調整

1.6のリリースからTypeScriptコンパイラは、 'commonjs'をターゲットとする場合に異なるルールセットを使用してモジュール名を解決します。 これらのルールは、 Nodeによって使用されるモジュール・ルックアップ・プロシージャをモデル化しようと試みたものです。 これは事実上、ノードモジュールがその型付けに関する情報を含むことが可能で、 TypeScriptコンパイラがそれを見つけることができることを意味します。

ただし、ユーザーは--moduleResolutionコマンドラインオプションを使用して、 コンパイラが選択したモジュール解決ルールを上書きすることができます。 指定可能な値は下記のとおりです。

  • 'classic' - 1.6より前のTypeScriptコンパイラによるモジュール解決ルールが使用されます。
  • 'node' - nodeライクなモジュール解決。

アンビエント・クラスとインターフェース宣言のマージ

アンビエントクラス宣言のインスタンス側を、インタフェース宣言を使用して拡張することができます。 このクラスのコンストラクタオブジェクトは変更されません。 下記はその一例になります。

declare class Foo {
    public x : number;
}

interface Foo {
    y : string;
}

function bar(foo : Foo)  {
    foo.x = 1;   // OK、クラスFoo内の宣言
    foo.y = "1"; // OK、インターフェースFoo内の宣言
}

ユーザー定義の型の保護(type guard)関数

TypeScript 1.6では、typeofinstanceofに加えて、 ifブロック内で変数の型を絞り込む新しい方法が追加されました。

ユーザー定義による型の保護(type guard)関数は、x is T形式の戻り値のアノテーション付きのものであり、 xはシグネチャの中で宣言されたパラメーター、Tは何らかの型になります。

ユーザー定義による型の保護の関数がifブロック内で変数に対して実行されると、 その変数の型はTに絞り込まれます。

function isCat(a: any): a is Cat {
  return a.name === 'kitty';
}

var x: Cat | Dog;
if(isCat(x)) {
  x.meow(); // OK、xはこのブロック内ではCat
}

tsconfig.json内のexcludeプロパティのサポート

filesプロパティを指定しないtsconfig.jsonファイル(つまり、全てのサブディレクトリ内の*.tsファイルを暗黙的に参照)に、 コンパイルから除外するファイル・ディレクトリを指定するexcludeプロパティを指定することが可能になりました。

excludeプロパティは、それぞれがtsconfig.jsonファイルからの相対場所のファイルまたはフォルダ名を指定する文字列の配列でなければいけません。 下記はその一例になります。

{
    "compilerOptions": {
        "out": "test.js"
    },
    "exclude": [
        "node_modules",
        "test.ts",
        "utils/t2.ts"
    ]
}

除外(exclude)リストはワイルドカードをサポートしません。 ファイル・ディレクトリの単純な一覧でなければいけません。

--initコマンドラインオプション

ディレクトリ内でtsc --initを実行すると、このディレクトリ内に初期設定のtsconfig.jsonを作成します。 tsconfig.jsonの作成時に最初の設定が格納されるように、 任意で--initのコマンドライン引数を渡します。

 Back to top

© https://github.com/Microsoft/TypeScript-Handbook

このページは、ページトップのリンク先のTypeScript-Handbook内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • ドキュメントの情報が古い可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。