Dodawanie adnotacji do kodu kompilatora zamknięcia

Uwaga: ta strona jest nieaktualna. Pełną listę znajdziesz na https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

Omówienie

Kompilator Closure może wykorzystywać informacje o typie danych zmiennych JavaScriptu, aby ulepszać optymalizację i ostrzeżenia. JavaScriptu nie można jednak deklarować.

JavaScript nie ma składni do zadeklarowania typu zmiennej, więc aby określić typ danych, musisz użyć komentarzy w kodzie.

Język używany w komponencie Closure Compiler pochodzi z adnotacji używanych w narzędziu do generowania dokumentów JSDoc, chociaż od tamtego czasu jest nieco bardziej rozpowszechniony. Zawiera teraz kilka adnotacji, których JSDoc nie obsługuje, i odwrotnie. Ten dokument opisuje zestaw adnotacji i wyrażeń typu zrozumiałych dla kompilatora Closure.

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

Tagi JSDoc

Kompilator zamknięty wyszukuje informacje o typie w tagach JSDoc. Użyj tagów JSDoc opisanych w tabeli poniżej, aby ułatwić kompilatorowi optymalizację kodu i sprawdzenie, czy nie występują w nim błędy.

Ta tabela zawiera tylko tagi, które mają wpływ na zachowanie kompozytora Closure. Informacje o innych tagach JSDoc znajdziesz w dokumentacji zestawu narzędzi JSDoc.

Tag Opis
@abstract

Oznacza metodę jako abstrakcyjną. Kompilator może przypominać metody z właściwością goog.abstractMethod, które są adnotowane przy użyciu @abstract, aby zmniejszyć rozmiar kodu.

Kompilator wyświetla ostrzeżenie, jeśli metoda oznaczona jako @abstract ma niepuste wdrożenie.

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

Oznacza zmienną jako tylko do odczytu. Kompilator może umieścić zmienne @const, które optymalizuje kod JavaScript.

Deklaracja typu jest opcjonalna.

Kompilator generuje ostrzeżenie, jeśli do zmiennej oznaczonej wartością @const została przypisana więcej niż raz. Jeśli zmienna jest obiektem, pamiętaj, że kompilator nie zezwala na zmiany właściwości 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 dla każdej funkcji używanej ze słowem kluczowym new

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ć flagę --define='ENABLE_DEBUG=false', by zmienić wartość ENABLE_DEBUG na false. Definicją stałej może być liczba, ciąg lub wartość logiczna. Definicje są dozwolone tylko w zakresie globalnym.

Przykład:

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

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

Oznacza funkcję, metodę lub właściwość w taki sposób, aby podczas korzystania z niego tworzone było ostrzeżenie dotyczące kompilatora wskazującego, że narzędzie nie jest już potrzebne.

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

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 tworzą zbiór powiązanych ze sobą stałych. Po tagu @enum musi znajdować się wyrażenie typu.

Etykieta typu wyliczenia ma zastosowanie do każdej właściwości wyliczenia. Jeśli na przykład wyliczenie zawiera typ number, każda z podanych wartości musi być liczbą. Jeśli pominiesz typ wyliczenia, zostanie przyjęta wartość number.

Przykład:

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

Podany kod

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

Po uruchomieniu kompilatora z flagą --generate_exports zostanie wygenerowany kod:

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

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

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

Kod korzystający z adnotacji @export musi:

  1. obejmują closure/base.js lub
  2. zdefiniuj goog.exportSymbol i goog.exportProperty z tą samą metodą metody w ich własnej bazie kodu.
@extends

Oznacza zajęcia lub interfejs jako dziedziczone z innych. Klasa oznaczona etykietą @extends musi też być oznaczona znacznikiem @constructor lub @interface.

Uwaga: @extends nie powoduje, że klasa dziedziczy z innych. Adnotacja informuje jedynie kompilator, że podczas sprawdzania typu może potraktować jedną klasę jako drugą.

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

Przykład:

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

Oznacza, że tych zajęć nie można przedłużyć. W przypadku metod oznacza, że żadna podklasa nie może zastąpić tej metody.

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życie razem z znacznikiem @constructor w celu wskazania, że klasa implementuje interfejs.

Kompilator generuje ostrzeżenie, jeśli oznaczysz konstruktor tagiem @implements, a potem nie wykorzystasz wszystkich metod i właściwości określonych w interfejsie.

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 pojawić się tylko w deklaracjach właściwości rozszerzeń. Właściwość ma zadeklarowany typ, ale możesz przypisać do niego dowolny typ bez ostrzeżenia. Gdy uzyskujesz dostęp do usługi, zwracana jest wartość zadeklarowanego typu. Na przykład element.innerHTML można przypisać dowolny typ, ale zawsze zwraca ciąg znaków.

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

Wskazuje, że metoda lub właściwość klasy podrzędnej celowo ukrywa metodę lub właściwość klasy premium i ma dokładnie taką samą dokumentację. Pamiętaj, że tag @inheritDoc wymaga tagu @override.

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 korzysta z interfejsu, musi implementować wszystkie metody i właściwości zdefiniowane w prototypie interfejsu. Zobacz @implements.

Kompilator sprawdza, czy nie utworzono instancji interfejsu. Jeśli słowo kluczowe new jest używane w funkcji interfejsu, kompilator generuje ostrzeżenie.

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 się pojawić tylko w literałach obiektów.

Nazwa w nawiasach klamrowych nie jest nazwą tego typu, jak w przypadku innych adnotacji. Jest to nazwa obiektu. Określa obiekt, do którego pożyczone są właściwości. Na przykład @type {Foo} oznacza „wystąpienie Foo”, a @lends {Foo} oznacza „konstruktor Foo”.

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

Przykład:

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

Mówi kompilatorowi, aby wstawił powiązany komentarz przed skompilowanym kodem zaznaczonego pliku. Ta adnotacja pozwala zachować ważne informacje (takie jak licencje lub tekst praw autorskich) bez zmian kompilacji. Podziały wiersza są zachowywane.

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ć zwinięta przez kompilator w zmienną. Głównym zastosowaniem w @nocollapse jest możliwość eksportowania usług zmiennych. Pamiętaj, że właściwości zwiniętego pliku nadal można zmieniać przez kompilator. Jeśli opiszesz właściwość, która jest obiektem z atrybutem @nocollapse, wszystkie jej właściwości pozostaną niezmienione.

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 żadnych efektów ubocznych. Jeżeli ta wartość nie jest używana, kompilator może usunąć wywołania funkcji. Adnotacja jest dozwolona tylko w extern files.

Przykład:

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

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

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

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

Przykład:

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

Oznacza członka lub usługę jako prywatne. Dostęp do nazw oznaczonych jako @package ma tylko kod w tym samym katalogu. W szczególności kod w katalogach nadrzędnych i podrzędnych nie ma dostępu do nazw oznaczonych etykietą @package.

Konstruktory publiczne mogą mieć właściwości @package ograniczające metody, których mogą używać osoby wywołujące spoza katalogu. Z kolei konstruktory @package mogą mieć właściwości publiczne, aby uniemożliwić obiektom wywołującym spoza katalogu bezpośrednie tworzenie instancji typu.

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 są z użyciem metody, funkcji i konstruktora w celu określenia typów argumentów funkcji. Tagi @param muszą mieć kolejność zgodną z parametrami 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 (zobacz funkcję foo w przykładzie).

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 o niszczycielskim wzorcu możesz użyć dowolnej nazwy, która jest prawidłowym identyfikatorem JS.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Oznacza członka jako prywatnego. Dostęp do zmiennych i funkcji globalnych oznaczonych jako @private ma tylko kod w tym samym pliku. Konstruktory oznaczone @private można utworzyć tylko za pomocą kodu w tym samym pliku oraz elementów statycznych i instancji.

Publiczne właściwości statyczne konstruktorów oznaczonych jako @private są też dostępne z dowolnego miejsca, a operator instanceof ma zawsze dostęp do elementów @private.

Przykład:

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

@protected

Wskazuje, że użytkownik lub usługa są chronione.

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

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

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 nominalnego @interface, ale umożliwia stosowanie implementacji pośrednich. Oznacza to, że każda klasa zawierająca metody i właściwości zdefiniowane w prototopie interfejsu strukturalnego implementuje interfejs strukturalny, niezależnie od tego, czy używa tagu @implements. Typy rekordów i literały obiektów domyślnie implementują interfejs strukturalny, jeśli zawierają wymagane właściwości.

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 zwracanych definicji metody i funkcji. Po tagu @return musi znajdować się wyrażenie typu.

Możesz też dodać opis typu zwrotu w tekście (zobacz funkcję foo w przykładzie).

Jeśli funkcja, która nie jest zewnętrzne, nie ma wartości zwracającej, możesz pominąć tag @return, a kompilator przyjmie, że funkcja zwraca undefined.

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 jest używany do tworzenia obiektów o stałej liczbie właściwości. Gdy konstruktor (w tym przykładzie Foo) jest oznaczony adnotacją @struct, dostęp do właściwości obiektów Foo możesz uzyskać tylko za pomocą kropki, a nie w nawiasie. Nie możesz też dodać właściwości do instancji Foo po jej utworzeniu. Adnotacji można też używać bezpośrednio na literałach obiektów.

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.

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 uniknąć ostrzeżeń dotyczących kompilacji, musisz użyć adnotacji @this za każdym razem, gdy this pojawi się w funkcji, która nie jest metodą prototypową ani funkcją oznaczoną jako @constructor.

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łoszonych przez funkcję. Obecnie ta funkcja nie korzysta z tych informacji. Służy on wyłącznie do sprawdzania, czy funkcja zadeklarowana w pliku rozszerzeń ma efekty uboczne.

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 dodać w tekście adnotację typu, pomijając elementy {} i @type, tak jak w drugim przykładzie. Ten skrót można wykonać tylko wtedy, gdy zadeklarowano zmienną lub parametr funkcji. Jeśli zechcesz później zmienić typ treści, będziesz potrzebować typu przesyłania.

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 wewnątrz funkcji. Naprawiliśmy to ograniczenie w nowej wnioskowaniu typu.

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 specjalnie zapisywać, chyba że używasz słowa kluczowego goog.defineClass lub słowa kluczowego class, które generuje domyślnie klasy @struct.

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 („{ }”) zawierających kombinację kombinacji operatorów opisanych poniżej.

Zadeklaruj typ parametru funkcji za pomocą wyrażenia typu z tagiem @param. Aby zdefiniować typ zmiennej, właściwości lub wyrażenia, użyj wyrażenia typu z tagiem @type.

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

Kompilator wykorzystuje te adnotacje do sprawdzania typu programu. Pamiętaj, że kompilator Closure nie zawiera żadnych obietnic, że będzie w stanie znaleźć typ każdego wyrażenia w programie. Najlepiej zrobić to, sprawdzając, jak używane są zmienne i jakie adnotacje są powiązane z ich deklaracjami. Następnie używa wielu algorytmów wnioskowania dotyczących typu, aby określić rodzaj jak największej liczby wyrażeń. Niektóre z tych algorytmów są proste („jeśli x to liczba, a my to y = x;, to y to liczba”). Niektóre z nich są bardziej pośrednie („jeśli pierwszy parametr f jest udokumentowany jako wywołanie zwrotne, które musi przyjmować liczbę, a widzimy f(function(x) { /** ... */ });, wtedy x musi być liczbą”).

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

{Object<string, number>}
Obiekt, w którym klucze są ciągami znaków, a wartościami to liczby.

Parametr określa typ za pomocą zestawu argumentów typu. To coś podobnego do Javy.
Typ: związki {(number|boolean)}
Liczba lub wartość logiczna.

Wymagane nawiasy kwadratowe.
Wskazuje, że wartość może zawierać typ A LUB typ B.
Typ rekordu {{myNum: number, myObject}}
Anonimowy typ z usługą myNum, która ma wartość typu number, i usługą o nazwie myObject, która ma wartość dowolnego typu.

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

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

Typ null {?number}
Liczba lub null.

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

Wszystkie typy obiektów są domyślnie puste, niezależnie od tego, czy zostały zadeklarowane za pomocą operatora null. Typ obiektu to dowolny obiekt oprócz funkcji, ciągu, liczby lub wartości logicznej. Aby typ obiektu nie był null, użyj operatora nienull.

Nie dopuszcza się wartości null {!Object}
Obiekt, ale nigdy wartość null.

Wskazuje, że wartość jest typu A, a nie jest pusta.

Funkcje i wszystkie typy wartości (wartość logiczna, liczba i ciąg) nie są domyślnie puste, niezależnie od tego, czy zostały zadeklarowane za pomocą operatora bez wartości null. Aby wartość lub typ funkcji miał wartość null, użyj operatora nullable.

Typ funkcji {function(string, boolean)}
Funkcja, która przyjmuje 2 parametry (ciąg i wartość logiczna) i ma nieznaną wartość zwrotną.
Określa funkcję i typy parametrów funkcji.
Typ zwracania funkcji {function(): number}
Funkcja, która nie przyjmuje parametrów i zwraca liczbę.
Określa typ zwracanej wartości funkcji.
Typ funkcji this {function(this:goog.ui.Menu, string)}
Funkcja, która przyjmuje jeden parametr (ciąg znaków) i wykonuje się w kontekście kontekstu goog.ui.Menu.
Określa typ wartości this w funkcji.
Typ funkcji new {function(new:goog.ui.Menu, string)}
Funkcja, która przyjmuje jeden parametr (ciąg znaków) i tworzy nowe wystąpienie tagu goog.ui.Menu po wywołaniu za pomocą słowa kluczowego „nowe”.
Określa typ konstruktora.
Parametry zmiennej {function(string, ...number): number}
Funkcja, która przyjmuje jeden parametr (ciąg znaków), a następnie 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 zmiennej (w @param adnotacjach) @param {...number} var_args
Zmienna liczba parametrów na funkcję z adnotacjami.
Wskazuje, że funkcja z adnotacjami akceptuje zmienną liczbę parametrów i określa ich typ.
Opcjonalny parametr w adnotacji @param @param {number=} opt_argument
Opcjonalny parametr typu number.

Argument wskazuje, że argument opisany w adnotacji @param jest opcjonalny. Wywołanie funkcji może pominąć opcjonalny argument. Opcjonalny parametr nie może znajdować się na liście parametrów opcjonalnych.

Jeśli wywołanie metody pomija parametr opcjonalny, ma on 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;
}
Opcjonalny argument w typie funkcji {function(?string=, number=)}
Funkcja, która przyjmuje 1 opcjonalny ciąg znaków o wartości null i 1 opcjonalną liczbę jako argumenty.
Wskazuje, że argument w typie funkcji jest opcjonalny. Opcjonalny argument można pominąć z wywołania funkcji. Opcjonalny argument nie może poprzedzać opcjonalnego argumentu na liście argumentów.
Typ WSZYSTKO {*} Wskazuje, że zmienna może przyjmować dowolny typ.
Typ NIEZNANY {?} Wskazuje, że zmienna może przyjąć dowolny typ, a kompilator nie powinien sprawdzać, czy ma ona jakiekolwiek zastosowania.

Typ przesyłania

Aby przesłać wartość do określonego typu, użyj tej składni

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

Typy ogólne

Podobnie jak w przypadku Javy, Closure Compiler obsługuje ogólne typy, funkcje i metody. Ogólne działają na obiektach różnego typu, a jednocześnie zachowują bezpieczeństwo podczas kompilacji.

Za ich pomocą możesz wdrożyć uogólnione kolekcje zawierające odwołania do obiektów określonego typu oraz uogólnione algorytmy działające na obiektach danego typu.

Deklarowanie typu ogólnego

Typ można ustawić jako ogólny, dodając adnotację @template do konstruktora typu (w przypadku klas) lub w deklaracji interfejsu (w przypadku interfejsów). Przykład:

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

Adnotacja @template T wskazuje, że typ Foo ma typ ogólny i 1 szablon (T). Typu szablonu T można używać jako typu w zakresie definicji Foo. Przykład:

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

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

Metoda get zwraca obiekt typu T, a metoda set akceptuje tylko obiekty typu T.

Tworzenie instancji typu ogólnego

Ten sam przykład: Foo można utworzyć na kilka sposobów:

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

Oba powyższe wyrażenia konstruktora tworzą instancję Foo, której szablon T to string. Kompilator wymusi wywoływanie metod foo i dostęp do właściwości foo z uwzględnieniem szablonu. Przykład:

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

Instancje mogą też domyślnie być wpisane przez argumenty ich konstruktora. Rozważ inny typ (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 określany jako string, w wyniku czego utworzona instancja bar jest traktowana jako Bar<string>.

Wiele typów szablonów

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

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

Wszystkie typy szablonów ogólnych muszą być określone w tej samej adnotacji @template, w formie listy rozdzielanej przecinkami. Kolejność nazw typów szablonów jest ważna, ponieważ adnotacje na podstawie szablonu będą grupować typy szablonów z wartościami. Przykład:

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

Różnica typów ogólnych

Kompilator zamknięty egzekwuje pisanie ogólne. Oznacza to, że jeśli kontekst oczekuje elementu Foo<X>, nie możesz przekazać typu Foo<Y>, gdy X i Y są różne, nawet jeśli jeden jest podtypem. 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 można naprawić lub rozpowszechnić w ramach dziedziczenia. Oto przykład typu dziedziczenia, który naprawia typ szablonu jego supertypu:

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

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

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

Po rozszerzeniu A<string> B będzie zawierać metodę method, która przyjmuje parametr typu string.

Oto przykład typu dziedziczenia, który rozpowszechnia ten typ szablonu:

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

Po rozszerzeniu A<U> wystąpienia 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. Jeden typ nie może być kilkukrotnie implementowany z różnym typem szablonu. 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 nadać ogólny charakter, dodając do definicji adnotację @template. 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