Closure Compiler 向け JavaScript のアノテーション

注: このページは最新ではありません。詳細なリストについては、https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler をご覧ください。

概要

Closure Compiler は JavaScript 変数のデータ型情報を使用して、最適化と警告を強化できます。ただし、JavaScript には型を宣言する手段がありません。

JavaScript には変数の型を宣言する構文がないため、コード内でコメントを使用してデータ型を指定する必要があります。

Closure Compiler 型の言語は JSDoc ドキュメント生成ツールで使用されるアノテーションから取得されますが、その後変更されました。JSDoc がサポートしていないアノテーションと、その逆のアノテーションがいくつか含まれています。このドキュメントでは、Closure Compiler が認識できるアノテーションと型式のセットについて説明します。

  1. JSDoc タグ
  2. 型式
  3. 汎用型

JSDoc タグ

Closure コンパイラは JSDoc タグで型情報を検索します。下記のリファレンス テーブルに記載されている JSDoc タグを使用して、コンパイラでコードを最適化し、型エラーなどの間違いがないかどうかを確認してください。

この表には、Closure Compiler の動作に影響するタグのみが含まれています。その他の JSDoc タグの詳細については、JSDoc Toolkit ドキュメントをご覧ください。

タグ 説明
@abstract

メソッドを抽象としてマークします。メソッドを goog.abstractMethod に設定するのと同様に、コンパイラは @abstract アノテーションが付いたメソッドをプルーニングしてコードサイズを縮小できます。

@abstract とマークされたメソッドに空以外の実装がある場合、コンパイラは警告を生成します。

例:
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

変数を読み取り専用としてマークします。コンパイラは、@const 変数をインライン化して、JavaScript コードを最適化できます。

型宣言は省略可能です。

@const とマークされた変数に値が複数回代入されると、コンパイラは警告を生成します。変数がオブジェクトの場合、コンパイラはオブジェクトのプロパティの変更を禁止していません。

例:
/** @const */ var MY_BEER = 'stout';

/**
 * My namespace's favorite kind of beer.
 * @const {string}
 */
mynamespace.MY_BEER = 'stout';

/** @const */ MyClass.MY_BEER = 'stout';
@constructor

関数をコンストラクタとしてマークします。コンパイラは、new キーワードとともに使用される関数に @constructor アノテーションを必要とします。

例:

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define コンパイラがコンパイル時にオーバーライドできる定数を示します。 左側の例では、--define='ENABLE_DEBUG=false' フラグをコンパイラに渡して、ENABLE_DEBUG の値を false に変更できます。 定義済みの定数のタイプは、数値、文字列、ブール値のいずれかです。定義はグローバル スコープでのみ許可されます。

例:

/** @define {boolean} */
var ENABLE_DEBUG = true;

/** @define {boolean} */
goog.userAgent.ASSUME_IE = false;
@deprecated

関数、メソッド、プロパティをマークします。これにより、使用すべきでないコンパイラ警告が生成されます。

例:

/**
 * Determines whether a node is a field.
 * @return {boolean} True if the contents of
 *     the element are editable, but the element
 *     itself is not.
 * @deprecated Use isField().
 */
BN_EditUtil.isTopEditableField = function(node) {
  ...
};
@dict

@dict は、可変長のプロパティを持つオブジェクトの作成に使用されます。コンストラクタ(この例では Foo)に @dict アノテーションが付けられている場合、Foo オブジェクトのプロパティにアクセスするには、角かっこ表記を使用する必要があります。アノテーションは、オブジェクト リテラルで直接使用することもできます。

例:

/**
 * @constructor
 * @dict
 */
function Foo() {}
var obj1 = new Foo();
obj1['x'] = 123;
obj1.x = 234;  // warning

var obj2 = /** @dict */ { 'x': 321 };
obj2.x = 123;  // warning
@enum

列挙型の型を指定します。列挙型は、関連する一連の定数をプロパティとして構成するオブジェクトです。@enum タグの後にタイプ式を付ける必要があります。

列挙型の型ラベルは、列挙型の各プロパティに適用されます。たとえば、列挙型の型が number の場合は、列挙された各プロパティを数値にする必要があります。列挙型の型を省略すると、number と見なされます。

例:

/**
 * Enum for tri-state values.
 * @enum {number}
 */
project.TriState = {
  TRUE: 1,
  FALSE: -1,
  MAYBE: 0
};
@export

このコードの場合

/** @export */
foo.MyPublicClass.prototype.myPublicMethod = function() {
  // ...
};

コンパイラが --generate_exports フラグを指定して実行されると、コードが生成されます。

goog.exportProperty(foo.MyPublicClass.prototype, 'myPublicMethod',
  foo.MyPublicClass.prototype.myPublicMethod);

これにより、シンボルがコンパイルされていないコードにエクスポートされます。

/**
 * @export
 * @type {SomeType}
 */
の省略形として /** @export {SomeType} */ を作成できます。

@export アノテーションを使用するコードは、次のいずれかである必要があります。

  1. closure/base.js を含む
  2. goog.exportSymbolgoog.exportProperty の両方を、同じコードベース内の同じメソッド シグネチャで定義します。
@extends

クラスまたはインターフェースを別のクラスから継承するマークを付けます。@extends でマークされたクラスにも、@constructor または @interface のいずれかを指定する必要があります。

注: @extends では、クラスは別のクラスから継承されません。アノテーションは、型チェック中に 1 つのクラスを別のサブクラスとして処理できることをコンパイラに伝えます。

継承の実装例については、Closure Library の関数 goog.inherits() をご覧ください。

例:

/**
 * Immutable empty node list.
 * @constructor
 * @extends {goog.ds.BasicNodeList}
 */
goog.ds.EmptyNodeList = function() {
  ...
};
@final

このクラスを拡張できないことを示します。 メソッドについて、そのメソッドをオーバーライドできるサブクラスがないことを示します。

例:

/**
 * A class that cannot be extended.
 * @final
 * @constructor
 */
sloth.MyFinalClass = function() { ... }

/**
 * A method that cannot be overridden.
 * @final
 */
sloth.MyFinalClass.prototype.method = function() { ... };
@implements

@constructor とともに使用され、クラスがインターフェースを実装することを示します。

コンストラクタに @implements のタグを付けてから、インターフェースで定義されたすべてのメソッドとプロパティの実装に失敗すると、コンパイラは警告を生成します。

例:


/**
 * A shape.
 * @interface
 */
function Shape() {};
Shape.prototype.draw = function() {};

/**
 * @constructor
 * @implements {Shape}
 */
function Square() {};
Square.prototype.draw = function() {
  ...
};
@implicitCast

このアノテーションは externs プロパティ宣言にのみ表示できます。プロパティには宣言された型がありますが、警告なしで任意の型を割り当てることができます。プロパティにアクセスすると、宣言された型の値が返されます。たとえば、element.innerHTML には任意の型を割り当てることができますが、常に文字列を返します。

/**
 * @type {string}
 * @implicitCast
 */
Element.prototype.innerHTML;
@inheritDoc

サブクラスのメソッドまたはプロパティがスーパークラスのメソッドまたはプロパティを意図的に非表示にし、まったく同じドキュメントを持っていることを示します。@inheritDoc タグは @override タグを示します。

例:

/** @inheritDoc */
project.SubClass.prototype.toString = function() {
  ...
};
@interface

関数をインターフェースとしてマークする。インターフェースには、型に必要なメンバーを指定します。インターフェースを実装するクラスは、そのインターフェースのプロトタイプで定義されているすべてのメソッドとプロパティを実装する必要があります。詳細については、@implements をご覧ください。

コンパイラは、インターフェースがインスタンス化されていないことを確認します。new キーワードがインターフェース関数とともに使用されている場合、コンパイラは警告を生成します。

例:

/**
 * A shape.
 * @interface
 */
function Shape() {};
Shape.prototype.draw = function() {};

/**
 * A polygon.
 * @interface
 * @extends {Shape}
 */
function Polygon() {};
Polygon.prototype.getSides = function() {};
@lends

オブジェクト リテラルのキーは、他のオブジェクトのプロパティとして扱う必要があります。このアノテーションは、オブジェクト リテラルにのみ表示されます。

中かっこ内の名前は、他のアノテーションのような型名ではありません。オブジェクト名です。このプロパティは、プロパティが貸し出されるオブジェクトの名前を指定します。たとえば、@type {Foo} は「Foo のインスタンス」を意味しますが、@lends {Foo} は「コンストラクタ Foo」を意味します。

このアノテーションについて詳しくは、JSDoc Toolkit ドキュメントをご覧ください。

例:

goog.object.extend(
    Button.prototype,
    /** @lends {Button.prototype} */ ({
      isButton: function() { return true; }
    }));
@license または @preserve

マークされたファイルのコンパイル済みコードの前に、関連するコメントを挿入するようにコンパイラに指示します。このアノテーションを使用すると、コンパイル時の変更後も重要な通知(法的ライセンスや著作権テキストなど)を通知できます。改行は保持されます。

例:

/**
 * @preserve Copyright 2009 SomeThirdParty.
 * Here is the full license text and copyright
 * notice for this file. Note that the notice can span several
 * lines and is only terminated by the closing star and slash:
 */
@nocollapse

コンパイラが変数に折りたたむべきではないプロパティを示します。@nocollapse の主な用途は、変更可能なプロパティのエクスポートを可能にすることです。なお、折りたたまれていないプロパティの名前もコンパイラで変更できます。 オブジェクトであるプロパティに @nocollapse アノテーションを付けると、そのプロパティはすべて折りたたまれていないままになります。

例:

/**
 * A namespace.
 * @const
 */
var foo = {};

/**
 * @nocollapse
 */
foo.bar = 42;

window['foobar'] = foo.bar;
@nosideeffects

宣言された外部関数の呼び出しに副作用がないことを示します。このアノテーションを使用すると、戻り値が使用されていない場合、コンパイラは関数の呼び出しを削除できます。アノテーションは extern files でのみ使用できます。

例:

/** @nosideeffects */
function noSideEffectsFn1() {}

/** @nosideeffects */
var noSideEffectsFn2 = function() {};

/** @nosideeffects */
a.prototype.noSideEffectsFn3 = function() {};
@override

サブクラスのメソッドまたはプロパティがスーパークラスのメソッドまたはプロパティを意図的に非表示にすることを示します。他のアノテーションが含まれていない場合、メソッドまたはプロパティは自動的にスーパークラスからアノテーションを継承します。

例:

/**
 * @return {string} Human-readable representation of
 *     project.SubClass.
 * @override
 */
project.SubClass.prototype.toString = function() {
  ...
};
@package

メンバーまたはプロパティを非公開としてマークします。同じディレクトリ内のコードのみが、@package とマークされた名前にアクセスできます。特に、親ディレクトリと子ディレクトリ内のコードは、@package とマークされた名前にアクセスできません。

パブリック コンストラクタには、@package プロパティを持つことで、ディレクトリ外の呼び出し元が使用できるメソッドを制限できます。一方、@package コンストラクタは、パブリック プロパティを持つことで、ディレクトリ外の呼び出し元が型を直接インスタンス化できないようにします。

例:

/**
 * Returns the window object the foreign document resides in.
 *
 * @return {Object} The window object of the peer.
 * @package
 */
goog.net.xpc.CrossPageChannel.prototype.getPeerWindowObject = function() {
  // ...
};
@param

関数の引数のタイプを指定するために、メソッド、関数、コンストラクタの定義で使用されます。@param タグは、関数定義のパラメータと同じ順序にする必要があります。

@param タグの後にタイプ式を付ける必要があります。

または、パラメータの型をインラインでアノテーションすることもできます(この例では foo 関数をご覧ください)。

例:


/**
 * Queries a Baz for items.
 * @param {number} groupNum Subgroup id to query.
 * @param {string|number|null} term An itemName,
 *     or itemId, or null to search everything.
 */
goog.Baz.prototype.query = function(groupNum, term) {
  ...
};

function foo(/** number */ a, /** number */ b) {
  return a - b + 1;
}
破棄パターンのパラメータの場合、型 アノテーションの後に、有効な JS 識別子の任意の名前を使用できます。
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

メンバーを非公開に設定する。同じファイル内のコードのみが、@private とマークされたグローバル変数と関数にアクセスできます。@private としてマークされたコンストラクタは、同じファイル内のコードによって、またその静的メンバーとインスタンス メンバーによってのみインスタンス化できます。

@private としてマークされたコンストラクタのパブリック静的プロパティにも、どこからでもアクセスでき、instanceof 演算子でいつでも @private メンバーにアクセスできます。

例:

/**
 * Handlers that are listening to this logger.
 * @private {Array<Function>}
 */
this.handlers_ = [];

@protected

メンバーまたはプロパティが保護されることを示します。

@protected としてマークされたプロパティは、以下にアクセスできます。

  • 同じファイル内のすべてのコード
  • 静的メソッド、プロパティが定義されているクラスのサブクラスのインスタンス インスタンス。

例:

/**
 * Sets the component's root element to the given element.
 * Considered protected and final.
 * @param {Element} element Root element for the component.
 * @protected
 */
goog.ui.Component.prototype.setElementInternal = function(element) {
  // ...
};
@record

関数を構造インターフェースとしてマークします。構造インターフェースは名詞 @interface に似ていますが、暗黙的な実装が可能です。つまり、構造インターフェースのプロトコルで定義されるメソッドとプロパティを含むすべてのクラスが、@implements タグを使用するかどうかにかかわらず、構造インターフェースを実装するということです。 レコード型とオブジェクト リテラルには、必要なプロパティが含まれている場合に、構造インターフェースが暗黙的に実装されます。

例:

/**
 * Anything with a draw() method.
 * @record
 */
function Drawable() {};
Drawable.prototype.draw = function() {};

/**
 * A polygon.
 * @param {!Drawable} x
 */
function render(x) { x.draw(); };

var o = { draw() { /* ... */ } };
render(o);
@return

メソッドと関数の定義の戻り値の型を指定します。 @return タグの後にタイプ式を付ける必要があります。

あるいは、戻り値の型にアノテーションを付けることもできます(この例の関数 foo をご覧ください)。

外部にない関数に戻り値がない場合、@return タグを省略できます。コンパイラは関数が undefined を返すと想定します。

例:

/**
 * Returns the ID of the last item.
 * @return {string} The hex ID.
 */
goog.Baz.prototype.getLastId = function() {
  ...
  return id;
};

function /** number */ foo(x) { return x - 1; }
@struct

@struct は、固定の数のプロパティを持つオブジェクトの作成に使用されます。コンストラクタ(この例では Foo)に @struct アノテーションを付けると、ドット表記を使用して角かっこ表記ではなく、Foo オブジェクトのプロパティにアクセスできます。また、作成後に Foo インスタンスにプロパティを追加することはできません。アノテーションは、オブジェクト リテラルで直接使用することもできます。

例:

/**
 * @constructor
 * @struct
 */
function Foo(x) {
  this.x = x;
}
var obj1 = new Foo(123);
var someVar = obj1.x;  // OK
obj1.x = "qwerty";  // OK
obj1['x'] = "asdf";  // warning
obj1.y = 5;  // warning

var obj2 = /** @struct */ { x: 321 };
obj2['x'] = 123;  // warning
@template

汎用型をご覧ください。

例:

/**
 * @param {T} t
 * @constructor
 * @template T
 */
Container = function(t) { ... };
@this

関数内で、キーワード this が参照するオブジェクトのタイプを指定します。@this タグの後にタイプ式を付ける必要があります。

コンパイラ警告を防ぐには、プロトタイプ メソッドでも @constructor とマークされた関数でもない関数に this が出現するたびに、@this アノテーションを使用する必要があります。

例:

chat.RosterWidget.extern('getRosterElement',
    /**
     * Returns the roster widget element.
     * @this {Widget}
     * @return {Element}
     */
    function() {
      return this.getComponent().getElement();
    });
@throws

関数からスローされた例外を文書化するために使用されます。 タイプ チェッカーは現在、この情報を使用しません。 これは、外部ファイルで宣言された関数に副作用があるかどうかを判断するためにのみ使用されます。

例:

/**
 * @throws {DOMException}
 */
DOMApplicationCache.prototype.swapCache = function() { ... };
@type

変数、プロパティ、式のタイプを示します。@type タグの後にタイプ式を付ける必要があります。

変数または関数のパラメータを宣言する場合、2 番目の例のように、{}@type を省略して型アノテーションをインラインで記述できます。このショートカットは、変数または関数パラメータが宣言されている場合にのみ実行できます。後で型を調整する場合は、型キャストが必要になります。

例:

/**
 * The message hex ID.
 * @type {string}
 */
var hexId = hexId;
var /** string */ name = 'Jamie';
function useSomething(/** (string|number|!Object) */ something) {
...
}
@typedef

より複雑な型のエイリアスを宣言します。現在、typedef は関数内ではなく、トップレベルでのみ定義できます。新しい型推論でこの制限を修正しました。

例:

/** @typedef {(string|number)} */
goog.NumberLike;

/** @param {goog.NumberLike} x A number or a string. */
goog.readNumber = function(x) {
  ...
}
@unrestricted

クラスが @struct 型でも @dict 型でもないことを示します。通常はこれがデフォルトであるため、通常は明示的に記述する必要はありません。ただし、goog.defineClass または class キーワードを使用している場合は、デフォルトで @struct になるクラスが生成されます。

例:

/**
 * @constructor
 * @unrestricted
 */
function Foo(x) {
  this.x = x;
}
var obj1 = new Foo(123);
var someVar = obj1.x;  // OK
obj1.x = "qwerty";  // OK
obj1['x'] = "asdf";  // OK
obj1.y = 5;  // OK

型式

変数、プロパティ、式、関数パラメータのデータ型を型式で指定できます。型式は、以下で説明する型演算子の組み合わせを含む中かっこ(「 }」)で構成されます。

関数パラメータの型を宣言するには、@param タグで型式を使用します。変数、プロパティ、または式のタイプを宣言するには、@type タグで型式を使用します。

コード内で指定するタイプが多いほど、コンパイラが最適化できる箇所が増え、検出できるミスも増えます。

コンパイラは、これらのアノテーションを使用してプログラムの型チェックを行います。 なお、Closure Compiler では、プログラムのすべての式のタイプを認識できるようになるとは約束しません。ベスト プラクティスは、変数の使い方と、宣言に添付される型のアノテーションを確認することです。次に、いくつかの型推論アルゴリズムを使用して、可能な限り多くの式のタイプを計算します。これらのアルゴリズムの一部は簡単です(「x が数値で、y = x; の場合は y は数値です」)。一部は間接的です(「f の最初のパラメータをコールバックとして文書化する必要があり、数値を受け取る必要があり、f(function(x) { /** ... */ }); が表示されている場合、x は数字でなければなりません」)。

演算子名 構文の例 説明
型名 {boolean}
{Window}
{goog.ui.Menu}
タイプの名前を指定します。
タイプ: アプリケーション {Array<string>}
文字列の配列。

{Object<string, number>}
キーが文字列で、値が数値であるオブジェクト。

型の引数のセットを使用して型をパラメータ化します。Java ジェネリックに似ています。
タイプ: ユニオン {(number|boolean)}
数値またはブール値。

かっこは必須です。
値がタイプ A またはタイプ B を持つ可能性があることを示します。
レコードタイプ {{myNum: number, myObject}}
number 型の値を持つ myNum というプロパティと、任意の型を持つ myObject というプロパティの両方を持つ匿名型。

値に、指定された型の値を持つ指定されたメンバーがあることを示します。

中かっこは型構文の一部です。たとえば、length プロパティを持つオブジェクトの Array を表すには、
Array<{length}> と記述します。左の例では、外側の中かっこはこれが型式であることを示し、内側の中かっこはレコード型であることを示しています。

null 値許容型 {?number}
数値または null

値がタイプ A または null であることを示します。

Nullable 演算子を使用して宣言しているかどうかにかかわらず、デフォルトですべてのオブジェクト型は null 値許容です。オブジェクト型は、関数、文字列、数値、ブール値以外のすべてとして定義されます。オブジェクト タイプを null 値非許容にするには、非 null 値許容演算子を使用します。

null 値非許容型 {!Object}
null オブジェクトではなく、オブジェクト。

値が null ではなくタイプ A であることを示します。

関数とすべての値の型(ブール値、数値、文字列)は、null 値非許容の演算子で宣言されているかどうかにかかわらず、デフォルトで null 値非許容型です。値または関数型を null 値許容型にするには、Nullable 演算子を使用します。

関数型 {function(string, boolean)}
2 つのパラメータ(文字列とブール値)を受け取り、不明な戻り値を持つ関数。
関数と関数のパラメータの型を指定します。
関数の戻り値の型 {function(): number}
パラメータを受け取らず数値を返す関数。
関数の戻り値の型を指定します。
関数 this {function(this:goog.ui.Menu, string)}
1 つのパラメータ(文字列)を受け取り、goog.ui.Menu のコンテキストで実行する関数。
関数内の this の値の型を指定します。
関数 new {function(new:goog.ui.Menu, string)}
1 つのパラメータ(文字列)を受け取り、new キーワードで呼び出されたときに goog.ui.Menu の新しいインスタンスを作成する関数。
コンストラクタの指定された型を指定します。
変数パラメータ {function(string, ...number): number}
1 つのパラメータ(文字列)を受け取り、その後に数値である可変数のパラメータを取る関数。
関数型が可変パラメータを受け取り、変数パラメータの型を指定することを示します。
変数パラメータ(@param アノテーション内) @param {...number} var_args
アノテーション付き関数への可変パラメータの数。
アノテーション付き関数が可変パラメータを受け入れ、変数パラメータの型を指定します。
@param アノテーション内のオプション パラメータ @param {number=} opt_argument
number タイプのオプションのパラメータ。

@param アノテーションで記述された引数が省略可能であることを示します。関数呼び出しでは、省略可能な引数を省略できます。オプション パラメータは、パラメータ リスト内でオプション以外のパラメータの前に置くことはできません。

メソッド呼び出しで省略可能なパラメータを省略した場合、その引数の値は undefined になります。したがって、メソッドがクラスのプロパティにパラメータ値を保存する場合、そのプロパティの型宣言には undefined という値が含まれている必要があります。次に例を示します。

/**
 * Some class, initialized with an optional value.
 * @param {Object=} opt_value Some value (optional).
 * @constructor
 */
function MyClass(opt_value) {
  /**
   * Some value.
   * @type {Object|undefined}
   */
  this.myValue = opt_value;
}
関数型の省略可能な引数 {function(?string=, number=)}
1 つの省略可能な null 値許容文字列と 1 つのオプションの数字を引数として受け取る関数。
関数型の引数が省略可能であることを示します。関数呼び出しからオプションの引数を省略できます。省略可能な引数を、引数リストの引数以外の引数の前に置くことはできません。
ALL 型 {*} 変数が任意の型を取ることを示します。
UNKNOWN 型 {?} 変数は任意の型を取ることができ、コンパイラは変数の型チェックを行わないことを示します。

型キャスト

特定の型に値をキャストするには、この構文を使用します。

/** @type {!MyType} */ (valueExpression)
式を囲むかっこは常に必要です。

汎用型

Java と同様に、Closure Compiler は汎用型、関数、メソッドをサポートします。ジェネリックは、コンパイル時の型の安全性を維持しながら、さまざまな型のオブジェクトで動作します。

ジェネリックを使用すると、特定の型のオブジェクトへの参照を保持する一般化されたコレクションと、特定の型のオブジェクトで動作する一般化されたアルゴリズムを実装できます。

汎用型を宣言する

型を汎用化するには、型のアノテーション(クラスの場合)またはインターフェースの宣言(インターフェースの場合)に @template アノテーションを追加します。次に例を示します。

/**
 * @constructor
 * @template T
 */
Foo = function() { ... };

アノテーション @template T は、Foo が 1 つのテンプレート タイプ(T)を持つ汎用型であることを示します。テンプレート タイプ T は、Foo の定義の範囲内で使用できます。次に例を示します。

/** @return {T} */
Foo.prototype.get = function() { ... };

/** @param {T} t */
Foo.prototype.set = function(t) { ... };

get メソッドは T 型のオブジェクトを返し、メソッド setT 型のオブジェクトのみを受け入れます。

汎用型のインスタンス化

上記の例を再利用すると、Foo のテンプレート インスタンスをいくつかの方法で作成できます。

/** @type {!Foo<string>} */ var foo = new Foo();
var foo = /** @type {!Foo<string>} */ (new Foo());

上記のコンストラクタ ステートメントはどちらも、テンプレート タイプ TstringFoo インスタンスを作成します。コンパイラは、foo のメソッドの呼び出しを強制し、foo のプロパティにアクセスして、テンプレート化された型を尊重します。次に例を示します。

foo.set("hello");  // OK.
foo.set(3);        // Error - expected a string, found a number.
var x = foo.get(); // x is a string.

インスタンスはコンストラクタ引数によって暗黙的に入力することもできます。別の汎用タイプである Bar について考えてみます。

/**
 * @param {T} t
 * @constructor
 * @template T
 */
Bar = function(t) { ... };
var bar = new Bar("hello"); // bar is a Bar<string>

Bar コンストラクタの引数の型は string として推定されます。その結果、作成されたインスタンス barBar<string> として推定されます。

複数のテンプレート タイプ

ジェネリックには任意のタイプのテンプレートを指定できます。次のマップクラスには、2 つのテンプレート タイプがあります。

/**
 * @constructor
 * @template Key, Val
 */
MyMap = function() { ... };

汎用型のテンプレート型はすべて、カンマ区切りのリストとして同じ @template アノテーションで指定する必要があります。テンプレート タイプ名の順序は重要です。テンプレート タイプのアノテーションでは、この順序を使用してテンプレート タイプと値をペア設定します。次に例を示します。

/** @type {MyMap<string, number>} */ var map; // Key = string, Val = number.

汎用型の不変性

Closure Compiler では不変の汎用型が適用されます。つまり、コンテキストが Foo<X> 型を想定している場合、XY の型が互いに異なる場合でも、1 つの型 Foo<Y> を渡すことはできません。次に例を示します。

/**
 * @constructor
 */
X = function() { ... };

/**
 * @extends {X}
 * @constructor
 */
Y = function() { ... };

/** @type {Foo<X>} */ var fooX;
/** @type {Foo<Y>} */ var fooY;

fooX = fooY; // Error
fooY = fooX; // Error

/** @param {Foo<Y>} fooY */
takesFooY = function(fooY) { ... };

takesFooY(fooY); // OK.
takesFooY(fooX); // Error

汎用型の継承

汎用型は継承可能で、テンプレート型は継承型に固定または伝播できます。継承された型の例で、そのスーパータイプのテンプレート型を修正する例を次に示します。

/**
 * @constructor
 * @template T
 */
A = function() { ... };

/** @param {T} t */
A.prototype.method = function(t) { ... };

/**
 * @constructor
 * @extends {A<string>}
 */
B = function() { ... };

A<string> を拡張することで、B には、string 型のパラメータを取るメソッド method が含まれるようになります。

スーパータイプのテンプレート タイプを伝播する継承タイプの例を次に示します。

/**
 * @constructor
 * @template U
 * @extends {A<U>}
 */
C = function() { ... };

A<U> を拡張することで、テンプレート化された C のインスタンスには、テンプレート タイプ U のパラメータを受け取るメソッド method が含まれます。

インターフェースは同様の方法で実装と拡張が可能ですが、1 つの型が異なるテンプレート型を使用して同じインターフェースを複数回実装することはできません。次に例を示します。

/**
 * @interface
 * @template T
 */
Foo = function() {};

/** @return {T} */
Foo.prototype.get = function() {};

/**
 * @constructor
 * @implements {Foo<string>}
 * @implements {Foo<number>}
 */
FooImpl = function() { ... }; // Error - implements the same interface twice

汎用関数とメソッド

汎用型と同様に、関数とメソッドは、定義に @template アノテーションを追加することで汎用化できます。次に例を示します。

/**
 * @param {T} a
 * @return {T}
 * @template T
 */
identity = function(a) { return a; };

/** @type {string} */ var msg = identity("hello") + identity("world"); // OK
/** @type {number} */ var sum = identity(2) + identity(2); // OK
/** @type {number} */ var sum = identity(2) + identity("2"); // Type mismatch