클로저 컴파일러에 자바스크립트 주석 달기

참고: 오래된 페이지입니다. 전체 목록은 https://github.com/google/closure-compiler/wiki/Annotating-자바스크립트-for-the-Closure-Compiler에서 관리됩니다.

개요

클로저 컴파일러는 자바스크립트 변수에 관한 데이터 유형 정보를 사용하여 향상된 최적화와 경고를 제공할 수 있습니다. 그러나 자바스크립트에는 유형을 선언할 수 있는 방법이 없습니다.

자바스크립트에는 변수 유형을 선언하는 문법이 없으므로 코드의 주석을 사용하여 데이터 유형을 지정해야 합니다.

클로저 컴파일러의 유형 언어는 JSDoc 문서 생성 도구에서 사용한 주석에서 파생되었지만 그 이후 다양해졌습니다. 이제 JSDoc에서 지원하지 않는 주석이 몇 가지 포함되어 있으며 그 반대도 마찬가지입니다. 이 문서에서는 클로저 컴파일러에서 이해할 수 있는 주석 및 유형 표현식을 설명합니다.

  1. JSDoc 태그
  2. 유형 표현식
  3. 일반 유형

JSDoc 태그

클로저 컴파일러는 JSDoc 태그에서 유형 정보를 찾습니다. 아래 참조 표에 설명된 JSDoc 태그를 사용하면 컴파일러가 코드를 최적화하고 유형 오류 및 기타 실수를 확인하는 데 도움이 됩니다.

이 표에는 클로저 컴파일러의 동작에 영향을 미치는 태그만 포함되어 있습니다. 다른 JSDoc 태그에 관한 자세한 내용은 JSDoc Toolkit 문서를 참고하세요.

태그 설명
@abstract

메서드를 추상으로 표시합니다. 메서드를 goog.abstractMethod로 설정하는 것과 마찬가지로 컴파일러는 @abstract 주석이 달린 메서드를 프루닝하여 코드 크기를 줄일 수 있습니다.

@abstract로 표시된 메서드에 비어 있지 않은 구현이 있으면 컴파일러에서 경고를 생성합니다.

예를 들면 다음과 같습니다.
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

변수를 읽기 전용으로 표시합니다. 컴파일러는 자바스크립트 코드를 최적화하는 @const 변수를 인라인 처리할 수 있습니다.

유형 선언은 선택사항입니다.

@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의 유형을 지정합니다. enum은 속성이 관련 상수 집합을 구성하는 객체입니다. @enum 태그 다음에는 유형 표현식이 와야 합니다.

enum의 유형 라벨은 enum의 각 속성에 적용됩니다. 예를 들어 enum에 number 유형이 있으면 열거형 각 속성이 숫자여야 합니다. enum 유형을 생략하면 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 {SomeType} */

/**
 * @export
 * @type {SomeType}
 */
의 약식 표현으로 작성할 수 있습니다.

@export 주석을 사용하는 코드는

  1. closure/base.js 포함
  2. 자체 코드베이스에서 동일한 메서드 서명으로 goog.exportSymbolgoog.exportProperty를 모두 정의합니다.
@extends

클래스 또는 인터페이스를 다른 클래스에서 상속하는 것으로 표시합니다. @extends로 표시된 클래스도 @constructor 또는 @interface로 표시해야 합니다.

참고: @extends는 클래스가 다른 클래스에서 상속받지 않도록 합니다. 주석은 유형 확인 중에 한 클래스를 다른 클래스의 서브클래스로 취급할 수 있다고 컴파일러에 알려줍니다.

상속 구현 예는 클로저 라이브러리 함수 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

이 주석은 extern 속성 선언에만 표시될 수 있습니다. 속성에 선언된 유형이 있지만 경고 없이 모든 유형을 할당할 수 있습니다. 속성에 액세스하면 선언된 유형의 값이 반환됩니다. 예를 들어 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 도구함 문서를 참고하세요.

예를 들면 다음과 같습니다.

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 참고).

extern에 없는 함수에 반환 값이 없으면 @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 태그 다음에는 유형 표현식이 와야 합니다.

컴파일러 경고를 방지하려면 this가 프로토타입 메서드가 아닌 @constructor로 표시된 함수에 표시될 때마다 @this 주석을 사용해야 합니다.

예를 들면 다음과 같습니다.

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

함수에서 발생한 예외를 문서화하는 데 사용됩니다. 유형 검사기는 현재 이 정보를 사용하지 않습니다. extern 파일에 선언된 함수가 부작용이 있는지 확인하는 데만 사용됩니다.

예를 들면 다음과 같습니다.

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

변수, 속성 또는 표현식의 유형을 식별합니다. @type 태그 다음에는 유형 표현식이 와야 합니다.

변수 또는 함수 매개변수를 선언할 때 두 번째 예에서와 같이 {}@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 태그와 함께 유형 표현식을 사용하여 변수, 속성 또는 표현식의 유형을 선언합니다.

코드에 유형을 더 많이 지정할수록 컴파일러에서 더 많은 최적화를 수행할 수 있고 더 많은 실수를 발견할 수 있습니다.

컴파일러는 이러한 주석을 사용하여 프로그램을 유형 확인합니다. 클로저 컴파일러는 프로그램의 모든 표현식 유형을 파악할 수 있다고 약속하지 않습니다. 변수가 사용되는 방식과 선언에 연결된 유형 주석을 살펴보는 것이 최선의 방법입니다. 그런 다음 여러 유형의 추론 알고리즘을 사용하여 최대한 많은 표현식의 유형을 파악합니다. 이러한 알고리즘 중 일부는 간단합니다('x가 숫자이고 y = x;가 보이면 y는 숫자'). 일부는 간접적입니다(예: f의 첫 번째 매개변수가 숫자를 받아야 하는 콜백으로 문서화되고 f(function(x) { /** ... */ });가 표시되면 x는 숫자여야 함).

연산자 이름 구문 예 설명
유형 이름 {boolean}
{Window}
{goog.ui.Menu}
유형 이름을 지정합니다.
애플리케이션 유형 {Array<string>}
문자열로 구성된 배열입니다.

{Object<string, number>}
키는 문자열이고 값은 숫자인 객체입니다.

유형 인수 집합을 사용하여 유형을 매개변수화합니다. 자바 제네릭과 유사합니다.
유형 공용체 {(number|boolean)}
숫자 또는 부울입니다.

필수 괄호를 확인합니다.
값이 유형 A 또는 유형 B를 가질 수 있음을 나타냅니다.
레코드 유형 {{myNum: number, myObject}}
유형이 numbermyNum 속성과 모든 유형의 값을 가진 myObject이라는 속성이 모두 포함된 익명 유형입니다.

값에 지정된 유형의 값과 함께 지정된 구성원이 있음을 나타냅니다.

중괄호는 유형 구문의 일부입니다. 예를 들어 length 속성이 있는 객체의 Array을 나타내려면
Array<{length}>을 작성하면 됩니다. 왼쪽 예에서 외부 중괄호는 유형 표현식임을 나타내고, 중괄호는 레코드 유형임을 나타냅니다.

null을 허용하는 유형 {?number}
숫자 또는 null입니다.

값이 유형 A 또는 null임을 나타냅니다.

모든 객체 유형은 null 허용 여부 연산자로 선언되었는지 여부와 관계없이 기본적으로 null을 허용합니다. 객체 유형은 함수, 문자열, 숫자, 부울을 제외한 모든 값으로 정의됩니다. 객체 유형을 null을 허용하지 않도록 하려면 null을 허용하지 않는 연산자를 사용합니다.

null을 허용하지 않는 유형 {!Object}
객체이지만 null 값은 아닙니다.

값이 null이 아닌 A 유형임을 나타냅니다.

함수와 모든 값 유형 (부울, 숫자, 문자열)은 null을 허용하지 않는 연산자로 선언되었는지 여부에 관계없이 기본적으로 null을 허용하지 않습니다. 값 또는 함수 유형을 null을 허용하는 값으로 설정하려면 Nullable 연산자를 사용합니다.

함수 유형 {function(string, boolean)}
두 매개변수 (문자열, 부울)를 사용하며 알 수 없는 반환 값이 있는 함수
함수 및 함수 매개변수 유형을 지정합니다.
함수 반환 유형 {function(): number}
매개변수를 사용하지 않고 숫자를 반환하는 함수입니다.
함수의 반환 값 유형을 지정합니다.
함수 this 유형 {function(this:goog.ui.Menu, string)}
하나의 매개변수 (문자열)를 가져오고 goog.ui.Menu의 컨텍스트에서 실행되는 함수입니다.
함수 내의 this 값 유형을 지정합니다.
함수 new 유형 {function(new:goog.ui.Menu, string)}
하나의 매개변수 (문자열)를 사용하고 'new' 키워드를 사용하여 호출할 때 새 goog.ui.Menu 인스턴스를 생성하는 함수입니다.
생성자의 생성된 유형을 지정합니다.
변수 매개변수 {function(string, ...number): number}
하나의 매개변수 (문자열)를 취한 다음 가변적인 수의 매개변수를 사용해야 하는 함수입니다.
함수 유형이 가변적인 수의 매개변수를 사용하는 것을 나타내며, 변수 매개변수의 유형을 지정합니다.
변수 매개변수 (@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=)}
선택사항으로 null을 허용하는 문자열 1개와 선택적 숫자 하나를 인수로 사용하는 함수입니다.
함수 유형의 인수는 선택사항임을 나타냅니다. 선택적 인수를 함수 호출에서 생략할 수 있습니다. 선택적 인수는 인수 목록의 선택적인 인수 앞에 올 수 없습니다.
전체 유형 {*} 변수가 모든 유형을 사용할 수 있음을 나타냅니다.
UNKNOWN 유형 {?} 변수가 모든 유형을 취할 수 있으며 컴파일러가 용도를 유형 검사해서는 안 된다는 것을 나타냅니다.

유형 변환

값을 특정 유형으로 변환하려면 다음 구문을 사용하세요.

/** @type {!MyType} */ (valueExpression)
표현식 괄호는 항상 필수입니다.

일반 유형

자바와 마찬가지로 클로저 컴파일러는 일반 유형, 함수, 메서드를 지원합니다. 제네릭은 다양한 유형의 객체에서 작동하면서 컴파일 시간 유형 안전성을 유지합니다.

제네릭을 사용하여 특정 유형의 객체에 대한 참조를 보유하는 일반화된 컬렉션과 특정 유형의 객체에 대해 작동하는 일반화된 알고리즘을 구현할 수 있습니다.

일반 유형 선언

유형을 유형의 생성자 (클래스의 경우) 또는 인터페이스 선언 (인터페이스의 경우)에 @template 주석을 추가하여 유형을 일반으로 만들 수 있습니다. 예를 들면 다음과 같습니다.

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

@template T 주석은 Foo이 템플릿 유형이 T인 일반 유형임을 나타냅니다. 템플릿 유형 TFoo의 정의 범위 내의 유형으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.

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

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

get 메서드는 T 유형의 객체를 반환하고 set 메서드는 T 유형의 객체만 허용합니다.

일반 유형 인스턴스화

위의 예시를 재사용하면 다음과 같이 여러 가지 방법으로 Foo의 템플릿 인스턴스를 만들 수 있습니다.

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

위의 생성자 문 모두 템플릿 유형이 TFoo 인스턴스를 string 생성합니다. 컴파일러는 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>로 추론됩니다.

여러 템플릿 유형

제네릭에는 원하는 수의 템플릿 유형이 있을 수 있습니다. 다음 지도 클래스에는 두 가지 템플릿 유형이 있습니다.

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

일반 유형의 모든 템플릿 유형은 동일한 @template 주석에 쉼표로 구분된 목록으로 지정해야 합니다. 템플릿 유형 주석의 순서가 중요하므로 템플릿 유형 이름의 순서가 중요합니다. 예를 들면 다음과 같습니다.

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

일반 유형의 불변

클로저 컴파일러는 불변 일반 입력을 적용합니다. 즉, 컨텍스트에서 Foo<X> 유형을 예상하는 경우 XY가 다른 유형인 경우 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>를 확장하면 Bstring 유형의 매개변수를 사용하는 method 메서드가 있습니다.

다음은 상위 유형의 템플릿 유형을 전파하는 상속 유형의 예입니다.

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

A<U>를 확장하여 C의 템플릿 인스턴스에는 템플릿 유형 U의 매개변수를 사용하는 method 메서드가 포함됩니다.

인터페이스는 유사한 방식으로 구현되고 확장될 수 있지만, 단일 유형이 다른 템플릿 유형으로 동일한 인터페이스를 여러 번 구현할 수는 없습니다. 예를 들면 다음과 같습니다.

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