Adnotacje w JavaScript dla kompilatora Closure Compiler

Uwaga: ta strona jest nieaktualna. Pełna lista jest dostępna na stronie https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

Przegląd

Kompilator Closure może używać informacji o typach danych zmiennych JavaScript, aby zapewniać lepszą optymalizację i ostrzeżenia. JavaScript nie ma jednak możliwości deklarowania typów.

JavaScript nie ma składni deklarowania typu zmiennej, dlatego musisz używać komentarzy w kodzie, aby określać typ danych.

Język typów kompilatora Closure Compiler wywodzi się z adnotacji używanych przez narzędzie do generowania dokumentów JSDoc, ale od tego czasu uległ zmianie. Zawiera teraz kilka adnotacji, których JSDoc nie obsługuje, i odwrotnie. W tym dokumencie opisujemy zestaw adnotacji i wyrażeń typów, które rozumie kompilator Closure Compiler.

  1. Tagi JSDoc
  2. Wyrażenia typu
  3. Typy ogólne

Tagi JSDoc

Kompilator Closure Compiler szuka informacji o typach w tagach JSDoc. Używaj tagów JSDoc opisanych w tabeli referencyjnej poniżej, aby pomóc kompilatorowi zoptymalizować kod i sprawdzić go pod kątem możliwych błędów typów i innych błędów.

Ta tabela zawiera tylko tagi, które wpływają na działanie kompilatora Closure Compiler. Informacje o innych tagach JSDoc znajdziesz w dokumentacji JSDoc Toolkit.

Tag Opis
@abstract

Oznacza metodę jako abstrakcyjną. Podobnie jak w przypadku ustawienia metody na goog.abstractMethod, kompilator może usuwać metody oznaczone adnotacją @abstract, aby zmniejszyć rozmiar kodu.

Jeśli metoda oznaczona adnotacją @abstract ma niepustą implementację, kompilator wyświetla ostrzeżenie.

Na przykład:
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

Oznacza zmienną jako tylko do odczytu. Kompilator może wstawiać zmienne w kodzie, co optymalizuje kod JavaScript.@const

Deklaracja typu jest opcjonalna.

Kompilator wyświetla ostrzeżenie, jeśli zmiennej oznaczonej symbolem @const przypisano wartość więcej niż raz. Jeśli zmienna jest obiektem, pamiętaj, że kompilator nie zabrania wprowadzania zmian we właściwościach obiektu.

Na przykład:
/** @const */ var MY_BEER = 'stout';

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

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

Oznacza funkcję jako konstruktor. Kompilator wymaga adnotacji @constructor w przypadku każdej funkcji używanej ze słowem kluczowym new.

Na przykład:

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define Wskazuje stałą, którą kompilator może zastąpić w czasie kompilacji. W przykładzie po lewej stronie możesz przekazać do kompilatora flagę --define='ENABLE_DEBUG=false', aby zmienić wartość ENABLE_DEBUG na false. Typ zdefiniowanej stałej może być liczbowy, tekstowy lub logiczny. Definicje są dozwolone tylko w zakresie globalnym.

Na przykład:

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

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

Oznacza funkcję, metodę lub właściwość, tak aby jej użycie powodowało ostrzeżenie kompilatora wskazujące, że nie należy jej już używać.

Na przykład:

/**
 * 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 służy do tworzenia obiektów o zmiennej liczbie właściwości. Jeśli konstruktor (Foo w przykładzie) jest oznaczony adnotacją @dict, do właściwości obiektów Foo możesz uzyskać dostęp tylko za pomocą notacji nawiasowej. Adnotacji można też używać bezpośrednio w przypadku literałów obiektów.

Na przykład:

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

Określa typ wyliczenia. Wyliczenie to obiekt, którego właściwości stanowią zbiór powiązanych stałych. Po tagu @enum musi znajdować się wyrażenie typu.

Etykieta typu wyliczenia dotyczy każdej właściwości wyliczenia. Jeśli np. wyliczenie ma typ number, każda z jego właściwości wyliczeniowych musi być liczbą. Jeśli typ wyliczenia zostanie pominięty, przyjmuje się wartość number.

Na przykład:

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

Dany kod

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

Gdy kompilator jest uruchamiany z flagą --generate_exports, generuje kod:

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

spowoduje wyeksportowanie symboli do nieskompilowanego kodu. Możesz napisać /** @export {SomeType} */ jako skrót od

/**
 * @export
 * @type {SomeType}
 */

Kod, który używa adnotacji @export, musi

  1. zawierać closure/base.js lub
  2. zdefiniować zarówno goog.exportSymbol, jak i goog.exportProperty za pomocą tej samej sygnatury metody w swojej bazie kodu.
@extends

Oznacza, że klasa lub interfejs dziedziczy po innej klasie. Klasa oznaczona wartością @extends musi być też oznaczona wartością @constructor lub @interface.

Uwaga: @extends nie powoduje, że klasa dziedziczy po innej klasie. Adnotacja informuje kompilator, że podczas sprawdzania typów może traktować jedną klasę jako podklasę innej.

Przykład implementacji dziedziczenia znajdziesz w funkcji goog.inherits() biblioteki Closure.

Na przykład:

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

Wskazuje, że tej klasy nie można rozszerzyć. W przypadku metod oznacza, że żadna podklasa nie może zastąpić tej metody.

Na przykład:

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

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

Używany z symbolem @constructor, aby wskazać, że klasa implementuje interfejs.

Jeśli oznaczysz konstruktor za pomocą @implements, a potem nie zaimplementujesz wszystkich metod i właściwości zdefiniowanych przez interfejs, kompilator wyświetli ostrzeżenie.

Na przykład:

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

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

Ta adnotacja może pojawiać się tylko w deklaracjach właściwości externs. Właściwość ma zadeklarowany typ, ale możesz przypisać do niej dowolny typ bez ostrzeżenia. Gdy uzyskasz dostęp do właściwości, otrzymasz wartość zadeklarowanego typu. Na przykład zmiennej element.innerHTML można przypisać dowolny typ, ale zawsze będzie ona zwracać ciąg znaków.

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

Wskazuje, że metoda lub właściwość podklasy celowo ukrywa metodę lub właściwość nadklasy i ma dokładnie taką samą dokumentację. Pamiętaj, że tag @inheritDoc oznacza tag @override.

Na przykład:

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

Oznacza funkcję jako interfejs. Interfejs określa wymaganych członków typu. Każda klasa, która implementuje interfejs, musi implementować wszystkie metody i właściwości zdefiniowane w prototypie interfejsu. Zobacz @implements.

Kompilator sprawdza, czy interfejsy nie są tworzone. Jeśli słowo kluczowe new jest używane z funkcją interfejsu, kompilator wyświetla ostrzeżenie.

Na przykład:

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

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

Wskazuje, że klucze literału obiektu powinny być traktowane jako właściwości innego obiektu. Ta adnotacja powinna pojawiać się tylko w przypadku literałów obiektów.

Zwróć uwagę, że nazwa w nawiasach klamrowych nie jest nazwą typu, jak w przypadku innych adnotacji. Jest to nazwa obiektu. Określa obiekt, do którego odnoszą się właściwości. Na przykład @type {Foo} oznacza „instancję Foo”, a @lends {Foo} oznacza „konstruktor Foo”.

Więcej informacji o tej adnotacji znajdziesz w dokumentacji JSDoc Toolkit.

Na przykład:

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

Nakazuje kompilatorowi wstawić powiązany komentarz przed skompilowanym kodem oznaczonego pliku. Ta adnotacja umożliwia zachowanie ważnych informacji (takich jak licencje prawne lub tekst dotyczący praw autorskich) bez zmian po skompilowaniu. Podziały wierszy są zachowywane.

Na przykład:

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

Oznacza właściwość, która nie powinna być zwijana przez kompilator do zmiennej. Głównym zastosowaniem @nocollapse jest umożliwienie eksportowania właściwości, które można zmieniać. Pamiętaj, że nazwy właściwości, które nie zostały zwinięte, mogą być nadal zmieniane przez kompilator. Jeśli dodasz adnotację do właściwości, która jest obiektem z właściwością @nocollapse, wszystkie jej właściwości również pozostaną rozwinięte.

Na przykład:

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

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

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

Wskazuje, że wywołanie zadeklarowanej funkcji zewnętrznej nie ma efektów ubocznych. Ta adnotacja umożliwia kompilatorowi usuwanie wywołań funkcji, jeśli wartość zwracana nie jest używana. Adnotacja jest dozwolona tylko w przypadku extern files.

Na przykład:

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

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

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

Wskazuje, że metoda lub właściwość podklasy celowo ukrywa metodę lub właściwość klasy nadrzędnej. Jeśli nie ma innych adnotacji, metoda lub właściwość automatycznie dziedziczy adnotacje z klasy nadrzędnej.

Na przykład:

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

Oznacza element lub właściwość jako dostępne tylko w pakiecie. Tylko kod w tym samym katalogu może uzyskiwać dostęp do nazw oznaczonych symbolem @package. W szczególności kod w katalogach nadrzędnych i podrzędnych nie może uzyskiwać dostępu do nazw oznaczonych symbolem @package.

Konstruktory publiczne mogą mieć właściwości @package, które ograniczają metody, z których mogą korzystać wywołujący spoza katalogu. Z drugiej strony @packagekonstruktory mogą mieć właściwości publiczne, aby uniemożliwić wywołującym spoza katalogu bezpośrednie tworzenie instancji typu.

Na przykład:

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

Używane w definicjach metod, funkcji i konstruktorów do określania typów argumentów funkcji. Tagi @param muszą być w tej samej kolejności co parametry w definicji funkcji.

Po tagu @param musi znajdować się wyrażenie typu.

Możesz też dodać adnotacje do typów parametrów w tekście (patrz funkcja foo w przykładzie).

Na przykład:

/**
 * 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;
}
W przypadku parametrów, które są wzorcem destrukcyjnym, po adnotacji o typie możesz użyć dowolnej nazwy będącej prawidłowym identyfikatorem JS.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Oznacza użytkownika jako prywatnego. Tylko kod w tym samym pliku może uzyskiwać dostęp do zmiennych globalnych i funkcji oznaczonych jako @private. Konstruktory oznaczone symbolem @private mogą być tworzone tylko przez kod w tym samym pliku oraz przez ich statyczne i instancyjne elementy członkowskie.

Do publicznych właściwości statycznych konstruktorów oznaczonych symbolem @private można uzyskać dostęp w dowolnym miejscu, a operator instanceof zawsze ma dostęp do elementów @private.

Na przykład:

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

Wskazuje, że członek lub usługa są chronione.

Usługa oznaczona symbolem @protected jest dostępna dla:

  • cały kod w tym samym pliku,
  • metody statyczne i metody instancji dowolnej podklasy klasy, w której zdefiniowano właściwość.

Na przykład:

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

Oznacza funkcję jako interfejs strukturalny. Interfejs strukturalny jest podobny do interfejsu nominalnego @interface, ale umożliwia implementacje niejawne. Oznacza to, że każda klasa, która zawiera metody i właściwości zdefiniowane w prototypie interfejsu strukturalnego, implementuje interfejs strukturalny, niezależnie od tego, czy używa tagu @implements. Typy rekordów i literały obiektów również niejawnie implementują interfejs strukturalny, jeśli zawierają wymagane właściwości.

Na przykład:

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

Określa typy zwracane przez definicje metod i funkcji. Po tagu @return musi znajdować się wyrażenie typu.

Możesz też dodać adnotację do typu zwracanego w tekście (patrz funkcja foo w przykładzie).

Jeśli funkcja, która nie znajduje się w pliku externs, nie zwraca żadnej wartości, możesz pominąć tag @return, a kompilator założy, że funkcja zwraca wartość undefined.

Na przykład:

/**
 * 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 służy do tworzenia obiektów o stałej liczbie właściwości. Jeśli konstruktor (Foo w przykładzie) jest oznaczony adnotacją @struct, do właściwości obiektów Foo możesz uzyskiwać dostęp tylko za pomocą notacji z kropką, a nie za pomocą notacji z nawiasami. Nie można też dodać właściwości do instancji Foo po jej utworzeniu. Adnotacji można też używać bezpośrednio w przypadku literałów obiektów.

Na przykład:

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

Zobacz Typy ogólne.

Na przykład:

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

Określa typ obiektu, do którego odnosi się słowo kluczowe this w funkcji. Po tagu @this musi znajdować się wyrażenie typu.

Aby zapobiec ostrzeżeniom kompilatora, musisz używać adnotacji @this, gdy this występuje w funkcji, która nie jest metodą prototypową ani funkcją oznaczoną jako @constructor.

Na przykład:

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

Służy do dokumentowania wyjątków zgłaszanych przez funkcję. Sprawdzanie typów nie korzysta obecnie z tych informacji. Jest używana tylko do określania, czy funkcja zadeklarowana w pliku externs ma efekty uboczne.

Na przykład:

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

Określa typ zmiennej, właściwości lub wyrażenia. Po tagu @type musi znajdować się wyrażenie typu.

Podczas deklarowania zmiennej lub parametru funkcji możesz zapisać adnotację typu w wierszu, pomijając znaki {}@type, jak w drugim przykładzie. Ten skrót można zastosować tylko w miejscu, w którym zadeklarowano zmienną lub parametr funkcji. Jeśli później zechcesz zmienić typ, musisz użyć rzutowania typu.

Na przykład:

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

Deklaruje alias dla bardziej złożonego typu. Obecnie typy typedef można definiować tylko na najwyższym poziomie, a nie w funkcjach. Usunęliśmy to ograniczenie w nowym wnioskowaniu o typach.

Na przykład:

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

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

Wskazuje, że klasa nie jest typu @struct ani @dict. Jest to ustawienie domyślne, więc zazwyczaj nie trzeba go wpisywać, chyba że używasz słowa kluczowego class, które domyślnie generuje klasy @struct.

Na przykład:

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

Wyrażenia typu

Typ danych dowolnej zmiennej, właściwości, wyrażenia lub parametru funkcji możesz określić za pomocą wyrażenia typu. Wyrażenie typu składa się z nawiasów klamrowych („{ }”), które zawierają kombinację operatorów typu opisanych poniżej.

Użyj wyrażenia typu z tagiem @param, aby zadeklarować typ parametru funkcji. Użyj wyrażenia typu z tagiem @type, aby zadeklarować typ zmiennej, właściwości lub wyrażenia.

Im więcej typów określisz w kodzie, tym więcej optymalizacji może wprowadzić kompilator i tym więcej błędów może wykryć.

Kompilator używa tych adnotacji do sprawdzania typów w programie. Pamiętaj, że kompilator Closure nie gwarantuje, że będzie w stanie określić typ każdego wyrażenia w Twoim programie. W tym celu analizuje sposób użycia zmiennych i adnotacje o typach dołączone do ich deklaracji. Następnie używa kilku algorytmów wnioskowania o typach, aby określić typ jak największej liczby wyrażeń. Niektóre z tych algorytmów są proste („jeśli x jest liczbą i widzimy y = x;, to y jest liczbą”). Niektóre są bardziej pośrednie („jeśli pierwszy parametr funkcji f jest udokumentowany jako wywołanie zwrotne, które musi przyjmować liczbę, a widzimy f(function(x) { /** ... */ });, to x musi być liczbą”).

Nazwa operatora Przykłady składni Opis
Wpisz nazwę {boolean}
{Window}
{goog.ui.Menu}
Określa nazwę typu.
Wpisz nazwę aplikacji {Array<string>}
Tablica ciągów znaków.

{Object<string, number>}
Obiekt, w którym klucze są ciągami tekstowymi, a wartości liczbami.

Parametryzuje typ za pomocą zestawu argumentów typu. Podobnie jak w przypadku typów generycznych w Javie.
Typ Union {(number|boolean)}
Liczba lub wartość logiczna.

Zwróć uwagę na nawiasy, które są wymagane.
Wskazuje, że wartość może mieć typ A LUB typ B.
Typ rekordu {{myNum: number, myObject}}
Typ anonimowy z właściwością o nazwie myNum i wartości typu number oraz właściwością o nazwie myObject i wartości dowolnego typu.

Wskazuje, że wartość ma określonych członków z wartościami określonych typów.

Nawiasy klamrowe są częścią składni typu. Aby na przykład oznaczyć Array obiektów, które mają właściwość length, możesz napisać:
Array<{length}>. W przykładzie po lewej stronie nawiasy klamrowe zewnętrzne wskazują, że jest to wyrażenie typu, a nawiasy klamrowe wewnętrzne wskazują, że jest to typ rekordu.

Typ dopuszczający wartość null {?number}
Liczba lub null.

Wskazuje, że wartość jest typu A lub null.

Domyślnie wszystkie typy obiektów mogą mieć wartość null, niezależnie od tego, czy zostały zadeklarowane za pomocą operatora Nullable. Typ obiektu to wszystko z wyjątkiem funkcji, ciągu znaków, liczby lub wartości logicznej. Aby ustawić typ obiektu jako nieakceptujący wartości null, użyj operatora Non-nullable.

Typ nieakceptujący wartości null {!Object}
 Obiekt, ale nigdy wartość null.

Wskazuje, że wartość jest typu A i nie jest wartością null.

Funkcje i wszystkie typy wartości (logiczne, liczbowe i ciągi znaków) domyślnie nie mogą mieć wartości null, niezależnie od tego, czy są zadeklarowane za pomocą operatora Non-nullable. Aby umożliwić przyjmowanie wartości null przez typ wartości lub funkcji, użyj operatora Nullable.

Typ funkcji {function(string, boolean)}
Funkcja, która przyjmuje 2 parametry (ciąg znaków i wartość logiczną) i ma nieznaną wartość zwrotną.
Określa funkcję i typy parametrów funkcji.
Typ zwracany przez funkcję {function(): number}
Funkcja, która nie przyjmuje żadnych parametrów i zwraca liczbę.
Określa typ wartości zwracanej funkcji.
Funkcja this Typ {function(this:goog.ui.Menu, string)}
Funkcja, która przyjmuje jeden parametr (ciąg znaków) i jest wykonywana w kontekście goog.ui.Menu.
Określa typ wartości this w funkcji.
Funkcja new Typ {function(new:goog.ui.Menu, string)}
Funkcja, która przyjmuje 1 parametr (ciąg znaków) i tworzy nową instancję goog.ui.Menu, gdy jest wywoływana ze słowem kluczowym „new”.
Określa skonstruowany typ konstruktora.
Parametry zmienne {function(string, ...number): number}
Funkcja, która przyjmuje 1 parametr (ciąg znaków), a potem zmienną liczbę parametrów, które muszą być liczbami.
Wskazuje, że typ funkcji przyjmuje zmienną liczbę parametrów, i określa typ parametrów zmiennych.
Parametry zmienne (w adnotacjach @param) @param {...number} var_args
Zmienna liczba parametrów funkcji z adnotacjami.
Wskazuje, że funkcja z adnotacjami akceptuje zmienną liczbę parametrów, i określa typ parametrów zmiennych.
Opcjonalny parametr w adnotacji @param @param {number=} opt_argument
Parametr opcjonalny typu number.

Wskazuje, że argument opisany przez adnotację @param jest opcjonalny. Wywołanie funkcji może pomijać argument opcjonalny. W liście parametrów parametr opcjonalny nie może poprzedzać parametru nieopcjonalnego.

Jeśli wywołanie metody pomija parametr opcjonalny, argument ten będzie miał wartość undefined. Jeśli więc metoda przechowuje wartość parametru we właściwości klasy, deklaracja typu tej właściwości musi zawierać możliwą wartość undefined, jak w tym przykładzie:

/**
 * 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;
}
Argument opcjonalny w typie funkcji {function(?string=, number=)}
Funkcja, która przyjmuje jako argumenty jeden opcjonalny ciąg znaków z możliwością wartości null i jedną opcjonalną liczbę.
Wskazuje, że argument w typie funkcji jest opcjonalny. Argument opcjonalny można pominąć w wywołaniu funkcji. Argument opcjonalny nie może poprzedzać argumentu nieopcjonalnego na liście argumentów.
Typ ALL {*} Wskazuje, że zmienna może przyjmować dowolny typ.
Typ UNKNOWN {?} Wskazuje, że zmienna może mieć dowolny typ, a kompilator nie powinien sprawdzać typów w żadnym przypadku jej użycia.

Rzutowanie typu

Aby przekształcić wartość w określony typ, użyj tej składni:

/** @type {!MyType} */ (valueExpression)
Nawiasy wokół wyrażenia są zawsze wymagane.

Typy generyczne

Podobnie jak Java, kompilator Closure obsługuje typy, funkcje i metody ogólne. Typy generyczne działają na obiektach różnych typów, zachowując bezpieczeństwo typów w czasie kompilacji.

Możesz używać typów ogólnych do implementowania uogólnionych kolekcji, które zawierają odwołania do obiektów określonego typu, oraz uogólnionych algorytmów, które działają na obiektach określonego typu.

Deklarowanie typu ogólnego

Typ można uogólnić, dodając adnotację @template do konstruktora typu (w przypadku klas) lub deklaracji interfejsu (w przypadku interfejsów). Na przykład:

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

Adnotacja @template T oznacza, że Foo jest typem ogólnym z 1 typem szablonu, T. Typ szablonu T może być używany jako typ w zakresie definicji Foo. Na przykład:

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

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

Metoda get zwróci obiekt typu T, a metoda set zaakceptuje tylko obiekty typu T.

Tworzenie instancji typu ogólnego

Korzystając z powyższego przykładu, instancję szablonu Foo można utworzyć na kilka sposobów:

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

Obie powyższe instrukcje konstruktora tworzą instancję Foo, której typ szablonu T to string. Kompilator będzie wymuszać, aby wywołania metod foo i dostęp do właściwości foo były zgodne z typem szablonu. Na przykład:

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

Typ instancji może być też określony niejawnie przez argumenty konstruktora. Rozważ inny typ ogólny, Bar:

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

Typ argumentu konstruktora Bar jest wnioskowany jako string, a w rezultacie utworzona instancja bar jest wnioskowana jako Bar<string>.

Wiele typów szablonów

Szablon ogólny może mieć dowolną liczbę typów szablonów. Ta klasa mapy ma 2 typy szablonów:

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

Wszystkie typy szablonów dla typu ogólnego muszą być określone w tym samym adnotacji @template jako lista rozdzielona przecinkami. Kolejność nazw typów szablonów jest ważna, ponieważ adnotacje typu szablonu będą używać tej kolejności do łączenia typów szablonów z wartościami. Na przykład:

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

Niezmienność typów ogólnych

Kompilator Closure Compiler wymusza niezmienne typowanie ogólne. Oznacza to, że jeśli kontekst oczekuje typu Foo<X>, nie możesz przekazać typu Foo<Y>, gdy XY są różnymi typami, nawet jeśli jeden jest podtypem drugiego. Na przykład:

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

Dziedziczenie typów ogólnych

Typy ogólne mogą być dziedziczone, a ich typy szablonów mogą być stałe lub propagowane do typu dziedziczącego. Oto przykład typu dziedziczącego, który poprawia typ szablonu swojego nadtypu:

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

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

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

Rozszerzając klasę A<string>, klasa B będzie miała metodę method, która przyjmuje parametr typu string.

Oto przykład typu dziedziczonego, który propaguje typ szablonu swojego typu nadrzędnego:

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

Dzięki rozszerzeniu A<U> instancje szablonu C będą miały metodę method, która przyjmuje parametr typu szablonu U.

Interfejsy można implementować i rozszerzać w podobny sposób, ale pojedynczy typ nie może implementować tego samego interfejsu wiele razy z różnymi typami szablonów. Na przykład:

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

Funkcje i metody ogólne

Podobnie jak w przypadku typów ogólnych, funkcje i metody można uczynić ogólnymi, dodając do ich definicji adnotację @template. Na przykład:

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