Closure Compilerを使う!

アノテーションによる型定義

最終更新:

aias-closurecompiler

- view
管理者のみ編集可

トップページ > 高度なトピック >

アノテーションによる型定義

Closure CompilerはJavaScript変数のデータ型やその他の情報を利用して、高度な最適化と警告機能を提供します。しかしJavaScriptには型を宣言する構文がありません。このため、あなたはコメントを使用してコード内にそれらを定義する必要があります。

Closure Compilerの型定義言語はドキュメント生成ツールであるJsDoc Toolkitで使用されているアノテーション(注釈)コメントから派生したものです。このページではClosure Compilerが解釈可能なアノテーションコメントと型表現のセットについて説明します。

  • このページは公式サイトのこちらを元に作成しました。
  • JsDoc Toolkitについてはこちらのサイトも参考にしてみてください。

目次:

JsDoc タグ

Closure CompilerはJsDocタグから型情報を探し出します。Compilerがコードの最適化と型エラーやその他の間違いの可能性をチェックする助けとするために、以下の表で説明されているJsDocタグを使用してください。

  • この表に含まれるタグはClosure Compilerの動作に影響を及ぼすものだけです。その他のJsDocタグについての情報は、JSDoc Toolkit documentationを参照してください。

@const

変数が読み取り専用であることを表します。Compilerは @const タグ付きの変数をインライン展開し、JavaScriptコードを最適化します。

Compilerは @const タグが付いた変数に1回より多く値が代入されている場合に警告を出力します。ただし変数がオブジェクトである場合、そのオブジェクトのプロパティを変更することは禁止されていない点に注意してください。

  • 構文

    @const

  • /** @const */

    var MY_BEER = 'stout';

    /**
     * My namespace's favorite kind of beer.
     * @const
     * @type {string}
     */

    mynamespace.MY_BEER = 'stout';

    /** @const */

    MyClass.MY_BEER = 'stout';

    型宣言と追加のコメントは必須ではありません。型が宣言されている場合、その変数の行はインライン化されずに残されます。

  • 実際にはこのアノテーションがない場合でも、大文字と" _ "だけからなる名前をもつ変数はCompilerによって定数として扱われます。詳しくはこちらを参照してください。

@constructor

関数がコンストラクタであることを表します。 new キーワードと共に使用される全ての関数について、Compilerは @constructor タグを要求します。

  • 構文

    @constructor

  • /**
     * A rectangle.
     * @constructor
     */

    function GM_Rect() {
      ...
    }

@define

コンパイル実行時にCompilerが上書き可能な定数であることを表します。下の例においてコマンドラインオプションとして --define="ENABLE_DEBUG=false" を指定すると、Compilerは ENABLE_DEBUG の値を false に変更します。

注意:--defineオプションはClosure Compiler Applicationのみで利用できます。

  • 構文
    @define {Type} Description
  • /** @define {boolean} */

    var ENABLE_DEBUG = true;

    /** @define {boolean} */

    goog.userAgent.ASSUME_IE = false;

@deprecated

マークされた関数、メソッド、プロパティが使用されるべきでないことを表します。廃止されたメソッドが使用されるとCompilerから警告が発行されます。

  • 構文

    @deprecated Description

  • /**
     * 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) {
      ...
    };

@enum

列挙型定数のデータ型を指定します。列挙型とはプロパティが関連する定数のセットで構成されているオブジェクトのことです。

@enum タグの後に続くのは必ず型表現でなければなりません。列挙型に対して指定された型はそれに含まれる全てのプロパティに適用されます。例えば列挙型に対し型として number を指定した場合、そこに列挙されているプロパティの値は数値でなければなりません。

型指定が省略された場合、それらは number であると見なされます。

  • 構文
    @enum {Type}
  • /**
     * Enum for tri-state values.
     * @enum {number}
     */

    project.TriState = {
      TRUE: 1,
      FALSE: -1,
      MAYBE: 0
    };

@extends

クラスまたはインターフェースが、別のクラスまたはインターフェースを継承していることを表します。 @extends タグが付いたクラスには必ず一緒に@constructorまたは@interfaceタグが付いていなければなりません。

注意: @extends タグはあるクラスが別のクラスを継承しているというような動作を実際のプログラム上で実現するものでありません。注釈コメントは単に、型チェックの際にあるクラスを別のクラスのサブクラスとして扱ってよいことをCompilerに伝えているだけです。継承を実装する例としては、Closure Libraryのgoog.inheritsメソッドを参照してください。

  • 構文
    @extends {Type}
  • /**
     * Immutable empty node list.
     * @constructor
     * @extends {goog.ds.BasicNodeList}
     */

    goog.ds.EmptyNodeList = function() {
      ...
    };

@implements

@constructorと共に使用し、クラスがあるインターフェースを実装していることを表します。 @implements タグが付いたコンストラクタがインターフェース側で定義されたメソッドとプロパティの一部でも実装していなかった場合、Compilerは警告を生成します。

  • 構文
    @implements {Type}
  • /**
     * A shape.
     * @interface
     */

    function Shape() {};
    Shape.prototype.draw = function() {};

    /**
     * @constructor
     * @implements {Shape}
     */

    function Square() {};
    Square.prototype.draw = function() {
      ...
    };

@inheritDoc

サブクラスのメソッドまたはプロパティが意図的にスーパークラスのそれを上書きしており、かつ両者が全く同じ注釈コメントを持っていることを示します。 @inheritDoc タグは@overrideタグを内包している点に注意してください。

  • 構文

    @inheritDoc

  • /** @inheritDoc */

    project.SubClass.prototype.toString() {
      ...
    };

@interface

関数がインターフェース定義であることを表します。インターフェースはあるデータ型が持っていなければならないメンバを定義します。あるインターフェースを実装するクラスは、インターフェースのprototype上に定義された全てのメソッドまたはプロパティを実装していなければなりません。@implementsを参照してください。

Compilerはインターフェースがインスタンス化されていないことを検証します。もし new キーワードがインターフェースを表す関数に対し使用されていた場合、Compilerは警告を生成します。

  • 構文

    @interface

  • /**
     * A shape.
     * @interface
     */

    function Shape() {};
    Shape.prototype.draw = function() {};

    /**
     * A polygon.
     * @interface
     * @extends {Shape}
     */

    function Polygon() {};
    Polygon.prototype.getSides = function() {};

@license or @preserve

付属するコメントをそのファイル内のコードをコンパイルした箇所の前に挿入するようCompilerに指示します。この注釈コメントは重要な情報(法的なライセンスや著作権表示のような)をコンパイル処理から保護するものです。改行は残されます。

  • 構文

    @license Description

  • /**
     * @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:
     */

@nosideeffects

この関数への呼び出しが副作用を持たないことを示します。この注釈コメントはCompilerに対し、もし戻り値が使われていなければこの関数の呼び出しを削除することを許可します。この注釈コメントはexternファイル内でのみ使用できます。

  • 構文

    @nosideeffects

  • /** @nosideeffects */


    function noSideEffectsFn1() {
      ...
    };

    /** @nosideeffects */

    var noSideEffectsFn2 = function() {
      ...
    };

    /** @nosideeffects */

    a.prototype.noSideEffectsFn3 = function() {
      ...
    };

@override

サブクラスのメソッドまたはプロパティが意図的にスーパークラスのそれを上書きしていることを表します。他の注釈コメントが含まれない場合、スーパークラスから注釈コメントが自動的に引き継がれます。

  • 構文

    @override

  • /**
     * @return {string} Human-readable representation of project.SubClass.
     * @override
     */

    project.SubClass.prototype.toString() {
      ...
    };

@param

メソッド、関数、コンストラクタで使用し、引数の型を指定します。 @param タグの後には必ず型表現が続かなくてはなりません。

  • 構文
    @param {Type} VarName Description
  • /**
     * 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) {
      ...
    };

@private

このメンバのスコープがprivateであることを表します。 @private が付いたシンボルへのアクセス権定義は以下のとおりです:

  • グローバルな変数や関数に @private を付けた場合、同一ファイル内のコードのみアクセスを許可します。
  • コンストラクタに @private を付けた場合、同一ファイル内のコードか、そのクラスの静的またはインスタンスメンバだけがそのクラスをインスタンス化できます。
  • コンストラクタに定義された静的プロパティに対しては、 @private が付いていてもどこからでもアクセスできます。
  • instanceof 演算子は @private が付いたメンバに自由にアクセスできます。
  • 構文

    @private

  • /**
     * Handlers that are listening to this logger.
     * @type {Array.<Function>}
     * @private
     */

    this.handlers_ = [];

@protected

このメンバのスコープがprotectedであることを表します。 @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) {
      ...
    };

@return

メソッドまたは関数の戻り値の型を指定します。 @return タグの後には型表現が続かなくてはなりません。戻り値がない場合は @return タグを使用してはいけません。

  • 構文
    @param {Type} Description
  • /**
     * Returns the ID of the last item.
     * @return {string} The hex ID.
     */

    goog.Baz.prototype.getLastId = function() {
      ...
      return id;
    };

@this

関数内で this キーワードとして参照されるオブジェクトの型を指定します。 @this タグの後には型表現が続かなくてはなりません。

Compilerの警告を回避するため、プロトタイプメソッドでなくかつ@constructorタグもない関数の中で this キーワードが出現する場合には必ず @this タグを記述してください。

  • 構文
    @this {Type}
  • chat.RosterWidget.extern('getRosterElement',

        /**
         * Returns the roster widget element.
         * @this {Widget}
         * @return {Element}
         */

        function() {
          return this.getComponent().getElement();
        });

@type

変数、プロパティ、式の値を指定します。 @type タグの後には型表現が続かなくてはなりません。

  • 構文
    @type {Type}
  • /**
     * The message hex ID.
     * @type {string}
     */

    var hexId = hexId;

@typedef

複合的な型指定のための別名を宣言します。 @typedef タグの後にはType Union形式の型表現が続かなくてはなりません。

  • 構文
    @typedef {Type}
  • /** @typedef {(string|number)} */

    goog.NumberLike;

    /** @param {goog.NumberLike} x A number or a string. */

    goog.readNumber = function(x) {
      ...
    }

型表現

どのような変数、プロパティ、式、関数パラメータに対しても「型表現」によるデータ型の指定を行うことができます。型表現の形式は、以下に説明する型指定の組み合わせを中括弧({})で括ったものです。

@paramタグと共に使用される型表現は関数パラメータの型を表します。@typeタグと共に使用される型表現は変数、プロパティ、式の型を表します。型指定が丁寧であればあるほど、Compilerはよりよく最適化を行えるようになり、また多くの間違いを見つけることができるようになります。

Type Name: 型名称

{boolean}
{Window}
{goog.ui.Menu}

型の名前を指定します。

Type Application: 配列メンバ

{Array.<string>}
文字列の配列

{Object.<string, number>}
キーが文字列、値が数値であるオブジェクト(連想配列)

型引数のセットを用いて、配列メンバの型を指定します。Javaのジェネリクスに似ています。

Type Union : 複数の型

{(number|boolean)}
数値または論理値

データ型がAまたはBであるようなケースを表します。

Record Type: 無名オブジェクトのプロパティの型

{{myNum: number, myObject}}
数値の値をもつmyNumプロパティと、型指定のないmyObjectプロパティをもつオブジェクト

指定された型をもつプロパティをメンバとするオブジェクトを表します。ここでは、中括弧はオブジェクトを表す記号として構文の一部となっています。例えば length というプロパティをもつオブジェクトの配列は、次のように表現できます。:Array.<{length}>
上の例では外側の中括弧はこれが型表現であることを表し、内側の中括弧はこれがオブジェクトであることを表します。

Nullable Type : nullを許容する

{?number}
数値またはnull

値が特定の型もしくはnullであることを表します。この記法が行われているかどうかに関わらず、全てのオブジェクト型はデフォルトでnullを許容します。オブジェクト型には関数・文字列・数値・論理値を除く全ての型が含まれます。nullを許容しないオブジェクト型を指定するには、Non-nullable Typeを使用します。

Non-nullable Type : nullを許容しない

{!Object}
オブジェクト、nullは不可

値が特定の型であり、nullであってはならないことを表します。この記法が行われているかどうかに関わらず、関数・文字列・数値・論理値はデフォルトでnullを許容しません。これらの型に対してnullを許容させるにはNullable Typeを使用します。

Function Type : 関数の型指定

{function(string, boolean)}
2つのパラメータ(文字列と論理値)を取る関数。戻り値は未定義。

値が関数であること、またそのパラメータの型を表します。

Function Return Type: 関数の戻り値

{function(): number}
パラメータを取らず、戻り値として数値を返す関数

指定された型の値を返す関数であることを表します。

Function this Type: 関数内のthis参照

{function(this:goog.ui.Menu, string)}
1つのパラメータ(文字列)を取り、goog.ui.Menuのコンテキストで実行される関数

指定された型の値を内部で this として参照する関数であることを表します。

Variable parameters: 不定数のパラメータ

{function(string, ...[number]): number}
文字列のパラメータを取り、その後に不定数の数値のパラメータを取る関数

個数が変動するパラメータを取る関数と、そのパラメータの型を表します。

Variable parameters (in @param annotations) : @paramタグで表す不定数パラメータ

@param {...number} var_args
個数が変動するパラメータ。データ型は数値。

この注釈コメントが付与された関数が個数の変動するパラメータをもつこと、またそのパラメータの型を表します。

Optional parameter in a @param annotation: 省略可能なパラメータ

@param {number=} opt_argument
省略可能な数値型のパラメータ

@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;
}

Optional argument in a function type: Function Type内で省略可能なパラメータを定義する

{function(?string=, number=)}
nullを許容する省略可能な文字列型のパラメータと、省略可能な数値型のパラメータを取る関数

Function Type記法内で、省略可能なパラメータを表現します。省略可能なパラメータはパラメータリストの中で省略不可能なパラメータより前には置けません。

The ALL Type: 全てのデータ型

{*}

その値がどのような型でも構わないことを表します。