TypeScript 1.4

共用体型(Union Types)

概要

共用体型(Union Types)は、幾つかの型の中の1つの型の値であることを示す強力な手法です。 例えば、コマンドライン(commandline)がstringstring[]、 またはstringを返す関数のいずれかとするプログラムを実行するAPIがあるとします。 それを次のように書くことができます。

interface RunOptions {
   program: string;
   commandline: string[]|string|(() => string);
}

共用体型(Union Types)への代入は非常に直感的に機能します。 共用体型(Union Types)のメンバの1つに割り当てることができるものは、全て割り当て可能です。

var opts: RunOptions = /* ... */;
opts.commandline = '-hello world'; // OK
opts.commandline = ['-hello', 'world']; // OK
opts.commandline = [42]; // Error, number is not string or string[]

共用体型(Union Types)を読み込むと、それらが共有するプロパティーを確認することができます。

if (opts.length === 0) { // OK, stringとstring[]は両方とも'length'プロパティを持ちます
  console.log("it's empty");
}

型の保護を使用すると、共用体型(Union Types)の値を使用して簡単に作業することができます。

function formatCommandline(c: string|string[]) {
    if (typeof c === 'string') {
        return c.trim();
    }
    else {
        return c.join(' ');
    }
}

厳格なジェネリクス

様々な型の状況を表すことができる共用体型(Union Types)を使用して、 特定の汎用的な呼び出しの厳格性を向上させることにしました。 これまでは、下記のようなコードが(驚くことに)エラー無しにコンパイルされていました。

function equal<T>(lhs: T, rhs: T): boolean {
  return lhs === rhs;
}

// これまで : エラー無し
// 新しい挙動: エラー、'string'と'number'で共通するベストな型がありません
var e = equal(42, 'hello');

共用体型(Union Types)では、関数宣言側と呼び出し側の両方で目的の動作を指定できるようになりました。

// 型が一致しなければいけない関数を'選択'
function choose1<T>(a: T, b: T): T { return Math.random() > 0.5 ? a : b }
var a = choose1('hello', 42); // Error
var b = choose1<string|number>('hello', 42); // OK

// 型が一致する必要の無い関数を'選択'
function choose2<T, U>(a: T, b: U): T|U { return Math.random() > 0.5 ? a : b }
var c = choose2('bar', 'foo'); // OK, c: string
var d = choose2('hello', 42); // OK, d: string|number

型推論の向上

共用体型(Union Types)は、複数の種類の値を持つコレクションなどに対しても、 より良い型推論の提供を可能にしてくれます。

var x = [1, 'hello']; // x: Array<string|number>
x[0] = 'world'; // OK
x[0] = false;   // エラー, booleanはstringでもnumberでもありません。

let宣言

JavaScriptにおいてvar宣言には、囲まれたスコープの先頭に"吊り上げられる"特徴があります。 例えば、下記は紛らわしいバグを発生させる可能性があります。

console.log(x); // ここでは'y'を出力する
/* 同じブロック内の後方 */
var x = 'hello';

TypeScriptでサポートされるようになったES6の新しいletキーワードは、 より直感的な"ブロック"の意味合いで値を宣言します。 let変数はその宣言の後でしか参照することができず、 定義されている構文ブロックにスコープされます。

if (foo) {
    console.log(x); // エラー、宣言前に参照することはできません
    let x = 'hello';
}
else {
    console.log(x); // エラー、xはブロック内で宣言されていません
}

letは、ECMAScript 6(--target ES6)を対象としている場合にのみ使用することができます。

const宣言

その他のTypeScriptでサポートされる新しいES6宣言にconstがあります。 const変数には値の割り当てが制限され、宣言された場所で初期化されなければいけません。 これは、初期化後に値を変更したくないケースで便利です。

const halfPi = Math.PI / 2;
halfPi = 2; // Error, can't assign to a `const`

constは、ECMAScript 6(--target ES6)を対象としている場合にのみ使用することができます。

テンプレート文字列

TypeScriptはES6のテンプレート文字列をサポートするようになりました。   任意の式を文字列に簡単に埋め込むことが出来るようになります。

var name = "TypeScript";
var greeting  = `Hello, ${name}! Your name has ${name.length} characters`;

pre-ES6より前を対象としたコンパイルでは、文字列が次のように分解されます。

var name = "TypeScript!";
var greeting = "Hello, " + name + "! Your name has " + name.length + " characters";

型の保護(Type Guards)

JavaScriptの一般的なパターンに、typeofまたはinstanceofを使用して実行時に式の型を調べることがあります。 TypeScriptはこれらの条件を理解できるようになり、ifブロックで使用すると型推論が変更されるようになりました。

下記は、typeofを使って変数を調べています。

var x: any = /* ... */;
if(typeof x === 'string') {
    console.log(x.subtr(1)); // Error, 'subtr' does not exist on 'string'
}
// x is still any here
x.unknown(); // OK

下記は共用体型(Union Types)に対してtypeofを使用して、elseと組み合わせて使用しています。

var x: string | HTMLElement = /* ... */;
if(typeof x === 'string') {
    // ここではxは文字列
}
else {
    // ここではxはHTMLElement
    console.log(x.innerHTML);
}

下記はクラスに対してinstanceofを使用して、共用体型(Union Types)と組み合わせて使用しています。

class Dog { woof() { } }
class Cat { meow() { } }
var pet: Dog|Cat = /* ... */;
if (pet instanceof Dog) {
    pet.woof(); // OK
}
else {
    pet.woof(); // Error
}

型のエイリアス(Type Aliases)

typeキーワードを使用して型のエイリアスを定義できるようになりました。

type PrimitiveArray = Array<string|number|boolean>;
type MyNumber = number;
type NgScope = ng.IScope;
type Callback = () => void;

型エイリアスは元の型とまったく同じであり、単なる代替名に過ぎません。

const enum (完全にインライン化されたenum)

enumは非常に便利ですが、プログラムによっては実際に生成されたコードで必要とされず、 enumのメンバが全てのインスタンスで数値として単純にインライン展開されたほうが、恩恵を受けることがあるでしょう。 新しいconst enum宣言は、型の安全性のために通常のenumと同じように動作しますが、コンパイル時に完全に消去されます。

const enum Suit { Clubs, Diamonds, Hearts, Spades }
var d = Suit.Diamonds;

次のようにコンパイルされます。

var d = 1;

可能であれば、enumの値も計算されるようになりました。

enum MyFlags {
  None = 0,
  Neat = 1,
  Cool = 2,
  Awesome = 4,
  Best = Neat | Cool | Awesome
}
var b = MyFlags.Best; // var b = 7; となる

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

TypeScriptコンパイラのデフォルトの動作では、 型エラー(例えば、文字列に数値を代入しようとする)があった場合でも、.jsファイルが出力されます。

これは"クリーン"ビルドの出力のみが必要とされるビルドサーバーやその他の状況で望ましくないことがあります。 新しいフラグnoEmitOnErrorは、エラーがあった場合にコンパイラが.jsコードを出力することを防ぎます。

これは現在のMSBuildプロジェクトでデフォルトとなっています。 出力がクリーンビルドでのみ生成されるため、MSBuildインクリメンタルビルドが期待通りに機能することを可能にしてくれます。

AMDモジュール名

デフォルトでは、AMDモジュールは匿名で生成されます。 これはバンドラー(r.jsなど)のように、結果として生じるモジュールを処理するために他のツールが使用される場合に、 問題を引き起こす可能性があります。

新しいamd-module nameタグを使用すると、任意のモジュール名をコンパイラに渡すことができます。

//// [amdModule.ts]
///<amd-module name='NamedModule'/>
export class C {
}

これはAMDのdefineの呼び出しの一部としてNamedModuleという名前をモジュールに割り当てることになります。

//// [amdModule.js]
define("NamedModule", ["require", "exports"], function (require, exports) {
    var C = (function () {
        function C() {
        }
        return C;
    })();
    exports.C = C;
});

 Back to top

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

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

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