Annotazione JavaScript per il compilatore Closure

Nota: questa pagina non è aggiornata. L'elenco completo è disponibile all'indirizzo https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

Panoramica

Il compilatore può utilizzare le informazioni sul tipo di dati relative alle variabili JavaScript per fornire un sistema di ottimizzazione e avvisi avanzati. JavaScript, tuttavia, non ha alcun modo per dichiarare i tipi.

Poiché JavaScript non ha sintassi per dichiarare il tipo di una variabile, devi utilizzare i commenti nel codice per specificare il tipo di dati.

Il linguaggio del tipo di Closure Compiler deriva dalle annotazioni utilizzate dallo strumento per la generazione di documenti JSDoc, anche se da allora si è discostato. Ora include diverse annotazioni non supportate da JSDoc e viceversa. Questo documento descrive l'insieme di annotazioni e di espressioni di tipo comprese dal compilatore.

  1. Tag JSDoc
  2. Digitare le espressioni
  3. Tipi generici

Tag JSDoc

Il compilatore cerca informazioni sui tipi di tag JSDoc. Utilizza i tag JSDoc descritti nella tabella di riferimento in basso per aiutare il compilatore a ottimizzare il codice e a verificare la presenza di eventuali errori di tipo e altri errori.

Questa tabella include solo i tag che influiscono sul comportamento del compilatore di chiusura. Per informazioni sugli altri tag JSDoc, consulta la documentazione di JSDoc Toolkit.

Tag Descrizione
@abstract

Contrassegna un metodo come astratto. Analogamente all'impostazione di un metodo su goog.abstractMethod, il compilatore può eliminare i metodi annotati con @abstract per ridurre le dimensioni del codice.

Il compilatore genera un avviso se un metodo contrassegnato con @abstract ha un'implementazione non vuota.

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

Contrassegna una variabile come di sola lettura. Il compilatore può incorporare variabili @const, in modo da ottimizzare il codice JavaScript.

La dichiarazione del tipo è facoltativa.

Il compilatore genera un avviso se a una variabile contrassegnata con @const viene assegnato un valore più di una volta. Se la variabile è un oggetto, tieni presente che il compilatore non vieta le modifiche alle proprietà dell'oggetto.

Ad esempio:
/** @const */ var MY_BEER = 'stout';

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

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

Contrassegna una funzione come costruttore. Il compilatore richiede un'annotazione @constructor per qualsiasi funzione utilizzata con la parola chiave new

Ad esempio:

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define Indica una costante che può essere sostituita dal compilatore al momento della compilazione. Con l'esempio a sinistra, puoi passare il flag --define='ENABLE_DEBUG=false' al compilatore per cambiare il valore di ENABLE_DEBUG in false. Il tipo di una costante definita può essere un numero, una stringa o un valore booleano. Le definizioni sono consentite solo nell'ambito globale.

Ad esempio:

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

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

Contrassegna una funzione, un metodo o una proprietà per fare in modo che, utilizzandola, venga generato un avviso del compilatore che indica che non deve più essere utilizzato.

Ad esempio:

/**
 * 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 viene utilizzato per creare oggetti con un numero variabile di proprietà. Quando un costruttore (Foo nell'esempio) ha un'annotazione @dict, puoi utilizzare solo la notazione tra parentesi per accedere alle proprietà degli oggetti Foo. L'annotazione può essere usata anche direttamente nei valori letterali degli oggetti.

Ad esempio:

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

Specifica il tipo di un'enumerazione. Un'enumerazione è un oggetto le cui proprietà costituiscono un insieme di costanti correlate. Il tag @enum deve essere seguito da un'espressione di tipo.

L'etichetta del tipo di un'enumerazione si applica a ogni proprietà dell'enumerazione. Ad esempio, se un'enumerazione ha il tipo number, ogni proprietà enumerata deve essere un numero. Se il tipo di un'enumerazione viene omesso, viene usato il valore number.

Ad esempio:

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

Dato questo codice

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

Quando il compilatore viene eseguito con il flag --generate_exports, genera il codice:

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

che esporteranno i simboli nel codice non compilato. Puoi scrivere /** @export {SomeType} */ come abbreviazione di

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

Il codice che utilizza l'annotazione @export deve:

  1. includi closure/base.js oppure
  2. definiscono sia goog.exportSymbol che goog.exportProperty con la stessa firma di metodo nel proprio codebase.
@extends

Contrassegna una classe o un'interfaccia come ereditata da un'altra classe. Una classe contrassegnata con @extends deve essere contrassegnata anche con @constructor o @interface.

Nota: @extends non comporta l'ereditarietà di una classe da un'altra. L'annotazione indica semplicemente al compilatore di trattare una classe come sottoclasse di un'altra durante il controllo dei tipi.

Per un esempio di implementazione dell'ereditarietà, consulta la funzione Chiusura della libreria goog.inherits().

Ad esempio:

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

Indica che non è consentito estendere il corso. Per i metodi, indica che a nessuna sottoclasse è consentito sostituire quel metodo.

Ad esempio:

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

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

Utilizzato con @constructor per indicare che una classe implementa un'interfaccia.

Il compilatore genera un avviso se tagghi un costruttore con @implements e poi non riesci a implementare tutti i metodi e le proprietà definiti dall'interfaccia.

Ad esempio:


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

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

Questa annotazione può apparire solo nelle dichiarazioni delle proprietà esterne. La proprietà ha un tipo dichiarato, ma puoi assegnarle qualsiasi tipo senza avviso. Quando accedi alla proprietà, ti viene restituito un valore del tipo dichiarato. Ad esempio, puoi assegnare element.innerHTML a qualsiasi tipo, ma restituisce sempre una stringa.

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

Indica che un metodo o una proprietà di una sottoclasse nasconde di proposito un metodo o una proprietà di tale classe e ha esattamente la stessa documentazione. Tieni presente che il tag @inheritDoc implica il tag @override.

Ad esempio:

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

Contrassegna una funzione come interfaccia. Un'interfaccia specifica i membri obbligatori di un tipo. Qualsiasi classe che implementa un'interfaccia deve implementare tutti i metodi e le proprietà definiti nel prototipo dell'interfaccia. Consulta @implements.

Il compilatore verifica che non sia stata creata un'istanza delle interfacce. Se la parola chiave new viene utilizzata con una funzione di interfaccia, il compilatore genera un avviso.

Ad esempio:

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

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

Indica che le chiavi del valore letterale di un oggetto devono essere considerate come proprietà di un altro oggetto. Questa annotazione deve essere visualizzata solo nei valori letterali degli oggetti.

Tieni presente che il nome tra parentesi graffe non è un nome tipo come nelle altre annotazioni. È il nome di un oggetto. Denomina l'oggetto a cui vengono prestate le proprietà. Ad esempio, @type {Foo} significa "un'istanza di Foo", ma @lends {Foo} significa "il costruttore Foo".

Per ulteriori informazioni su questa annotazione, consulta la documentazione relativa a JSDoc.

Ad esempio:

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

Indica al compilatore di inserire il commento associato prima del codice compilato per il file contrassegnato. Questa annotazione consente di mantenere invariate le compilazioni di notifiche legali (come licenze legali o testo del copyright). Le interruzioni di riga vengono conservate.

Ad esempio:

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

Indica una proprietà che non deve essere compressa dal compilatore in una variabile. L'utilizzo principale di @nocollapse è consentire l'esportazione di proprietà modificabili. Tieni presente che le proprietà non compresse possono comunque essere rinominate dal compilatore. Se annotate una proprietà che è un oggetto con @nocollapse, tutte le sue proprietà rimarranno non compresse.

Ad esempio:

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

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

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

Indica che una chiamata alla funzione esterna dichiarata non ha effetti collaterali. Questa annotazione consente al compilatore di rimuovere le chiamate alla funzione se il valore restituito non viene utilizzato. L'annotazione è consentita solo in extern files.

Ad esempio:

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

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

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

Indica che un metodo o una proprietà di una sottoclasse nasconde intenzionalmente un metodo o una proprietà della superclasse. Se non sono incluse altre annotazioni, il metodo o la proprietà ereditano automaticamente le annotazioni dalla relativa superclasse.

Ad esempio:

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

Contrassegna un membro o una proprietà come pacchetto privato. Solo il codice nella stessa directory può accedere ai nomi contrassegnati con @package. In particolare, il codice nelle directory padre e figlio non può accedere ai nomi contrassegnati con @package.

I costruttori pubblici possono avere proprietà @package per limitare i metodi che i chiamanti esterni alla directory possono utilizzare. D'altra parte, i costruttori @package possono avere proprietà pubbliche per impedire ai chiamanti esterni alla directory di creare un'istanza di un tipo direttamente.

Ad esempio:

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

Utilizzato con le definizioni di metodo, funzione e costruttore per specificare i tipi di argomenti della funzione. I tag @param devono essere nello stesso ordine dei parametri nella definizione della funzione.

Il tag @param deve essere seguito da un'espressione di tipo.

In alternativa, puoi annotare i tipi di parametri in linea (vedi la funzione foo nell'esempio).

Ad esempio:


/**
 * 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;
}
Per i parametri che rappresentano un pattern distruttivo, puoi utilizzare qualsiasi nome che sia un identificatore JS valido, dopo l'annotazione del tipo.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Contrassegna un membro come privato. Solo il codice nello stesso file può accedere alle variabili e alle funzioni globali contrassegnate con @private. I costruttori contrassegnati come @private possono avere un'istanza solo per il codice nello stesso file e per i membri statici e di istanza.

Puoi accedere ovunque alle proprietà statiche pubbliche dei costruttori contrassegnate con @private, inoltre l'operatore instanceof può sempre accedere ai membri @private.

Ad esempio:

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

@protected

Indica che un membro o una proprietà sono protetti.

Una proprietà contrassegnata come @protected è accessibile da:

  • tutto il codice nello stesso file
  • I metodi statici e di istanza di qualsiasi sottoclasse della classe in cui è definita la proprietà.

Ad esempio:

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

Contrassegna una funzione come interfaccia strutturale. Un'interfaccia strutturale è simile a una @interface nominale, ma consente implementazioni implicite. Questo significa che qualsiasi classe che include i metodi e le proprietà definiti nel prototomo dell'interfaccia strutturale implementa l'interfaccia strutturale, indipendentemente dall'utilizzo o meno del tag @implements. I tipi di record e i valori letterali degli oggetti implementano anche implicitamente un'interfaccia strutturale se contengono le proprietà obbligatorie.

Ad esempio:

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

Specifica i tipi di ritorno delle definizioni di metodo e funzione. Il tag @return deve essere seguito da un'espressione di tipo.

In alternativa, puoi annotare il tipo di ritorno incorporato (vedi la funzione foo nell'esempio).

Se una funzione che non è in uso non ha un valore restituito, puoi omettere il tag @return e il compilatore presume che la funzione restituisca undefined.

Ad esempio:

/**
 * 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 viene utilizzato per creare oggetti con un numero fisso di proprietà. Quando un costruttore (Foo nell'esempio) ha @struct, puoi utilizzare solo la notazione a punti per accedere alle proprietà degli oggetti Foo, non alla notazione a parentesi. Inoltre, non puoi aggiungere una proprietà a un'istanza Foo dopo la creazione. L'annotazione può essere usata anche direttamente nei valori letterali degli oggetti.

Ad esempio:

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

Vedi Tipi generici.

Ad esempio:

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

Specifica il tipo di oggetto a cui fa riferimento la parola chiave this. Il tag @this deve essere seguito da un'espressione di tipo.

Per evitare avvisi del compilatore, devi utilizzare un'annotazione @this ogni volta che this appare in una funzione che non è un metodo prototipo né una funzione contrassegnata come @constructor.

Ad esempio:

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

Utilizzato per documentare le eccezioni generate da una funzione. Al momento il controllore del tipo non utilizza queste informazioni. Viene utilizzato solo per capire se una funzione dichiarata in un file di tipo esterno ha effetti collaterali.

Ad esempio:

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

Identifica il tipo di variabile, proprietà o espressione. Il tag @type deve essere seguito da un'espressione di tipo.

Quando dichiari una variabile o un parametro di funzione, puoi scrivere l'annotazione del tipo in linea omettendo {} e @type, come nel secondo esempio. Questa scorciatoia può essere eseguita solo quando una variabile o un parametro di funzione è dichiarato. Se vuoi regolare il tipo in un secondo momento, hai bisogno di una digitazione.

Ad esempio:

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

Dichiara un alias per un tipo più complesso. Al momento, typedefs può essere definito solo al livello superiore, non all'interno delle funzioni. Abbiamo corretto questo limite nell'inferenza del nuovo tipo.

Ad esempio:

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

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

Indica che una classe non è di tipo @struct, né @dict. Questa è l'impostazione predefinita, pertanto non è generalmente necessario scriverla in modo esplicito, a meno che non utilizzi goog.defineClass o la parola chiave class, che producono entrambe classi @struct per impostazione predefinita.

Ad esempio:

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

Tipo di espressioni

Puoi specificare il tipo di dati di qualsiasi variabile, proprietà, espressione o parametro della funzione con un'espressione di tipo. Un'espressione di tipo è composta da parentesi graffe ("{ }") contenenti una combinazione di operatori di tipo descritti di seguito.

Utilizza un'espressione di tipo con il tag @param per dichiarare il tipo di un parametro della funzione. Utilizza un'espressione di tipo con il tag @type per dichiarare il tipo di una variabile, una proprietà o un'espressione.

Maggiore è il numero di tipi specificati nel codice, maggiori sono le ottimizzazioni che il compilatore può eseguire e il numero di errori che può riscontrare.

Il compilatore utilizza queste annotazioni per eseguire il controllo tipo del programma. Tieni presente che il componente Closure Compiler non fa alcuna promessa che possa stabilire il tipo di ogni espressione nel programma. Per ottenere i migliori risultati, è possibile controllare come vengono utilizzate le variabili e le annotazioni dei tipi allegate alle relative dichiarazioni. Quindi, utilizza una serie di algoritmi di deduzione di tipo per determinare il tipo di quante possibili espressioni. Alcuni di questi algoritmi sono semplici ("se x è un numero e vediamo y = x;, allora y è un numero"). Alcuni sono più indiretti ("se il primo parametro di f è documentato come un callback che deve contenere un numero, e vediamo f(function(x) { /** ... */ });, allora x deve essere un numero").

Nome operatore Esempi di sintassi Descrizione
Nome del tipo {boolean}
{Window}
{goog.ui.Menu}
Specifica il nome di un tipo.
Tipo di applicazione {Array<string>}
Una matrice di stringhe.

{Object<string, number>}
Un oggetto in cui le chiavi sono stringhe e i valori sono numeri.

Parametrizza un tipo con un insieme di argomenti type. Simile ai generici Java.
Tipo Union {(number|boolean)}
Un numero o un valore booleano.

Prendi nota delle parentesi necessarie.
Indica che un valore potrebbe essere di tipo A o tipo B.
Tipo di record {{myNum: number, myObject}}
Un tipo anonimo con una proprietà denominata myNum che ha un valore di tipo number e una proprietà denominata myObject che ha un valore di qualsiasi tipo.

Indica che il valore contiene i membri specificati con valori dei tipi specificati.

Le parentesi graffe fanno parte della sintassi dei tipi. Ad esempio, per indicare un Array di oggetti che hanno una proprietà length, puoi scrivere:
Array<{length}>. Nell'esempio a sinistra, le parentesi graffe esterne indicano che si tratta di un'espressione di tipo, mentre le parentesi graffe interne indicano che si tratta di un tipo di record.

Tipo null {?number}
Un numero o null.

Indica che un valore è di tipo A o null.

Tutti i tipi di oggetti sono nulli per impostazione predefinita, sia che siano dichiarati o meno con l'operatore Nullable. Per tipo di oggetto si intende qualsiasi elemento tranne una funzione, una stringa, un numero o un valore booleano. Per rendere non valido un tipo di oggetto, utilizza l'operatore Non-nullable.

Tipo non null {!Object}
Un oggetto, ma mai il valore null.

Indica che il valore A è di tipo A e non null.

Le funzioni e tutti i tipi di valori (booleani, numeri e stringhe) non sono null per impostazione predefinita, indipendentemente dal fatto che siano dichiarati o meno con l'operatore Non nullable. Per rendere nullo un valore o un tipo di funzione, utilizza l'operatore Nullable.

Tipo di funzione {function(string, boolean)}
Una funzione che accetta due parametri (una stringa e un valore booleano) e ha un valore restituito sconosciuto.
Specifica una funzione e i tipi dei parametri della funzione.
Tipo restituito funzione {function(): number}
Una funzione che non accetta parametri e restituisce un numero.
Specifica il tipo di valore di ritorno di una funzione.
Tipo di funzione this {function(this:goog.ui.Menu, string)}
Una funzione che accetta un solo parametro (una stringa) ed esegue nel contesto di goog.ui.Menu.
Specifica il tipo del valore di this all'interno della funzione.
Tipo di funzione new {function(new:goog.ui.Menu, string)}
Una funzione che accetta un parametro (una stringa) e crea una nuova istanza di goog.ui.Menu quando viene chiamata con la parola chiave "new".
Specifica il tipo costruito di un costruttore.
Parametri variabili {function(string, ...number): number}
Una funzione che accetta un parametro (una stringa) e un numero variabile di parametri che devono essere numeri.
Indica che un tipo di funzione accetta un numero variabile di parametri e specifica un tipo per i parametri della variabile.
Parametri variabili (in @param annotazioni) @param {...number} var_args
Un numero variabile di parametri per una funzione annotata.
Indica che la funzione annotata accetta un numero variabile di parametri e specifica un tipo per i parametri della variabile.
Parametro facoltativo in un'annotazione @param @param {number=} opt_argument
Un parametro facoltativo di tipo number.

Indica che l'argomento descritto da un'annotazione @param è facoltativo. In una chiamata funzione è possibile omettere un argomento facoltativo. Un parametro facoltativo non può essere preceduto da un parametro non facoltativo nell'elenco dei parametri.

Se in una chiamata di metodo viene omesso un parametro facoltativo, l'argomento avrà un valore undefined. Pertanto, se il metodo memorizza il valore del parametro in una proprietà di classe, la dichiarazione del tipo di quella proprietà deve includere un eventuale valore di undefined, come nell'esempio seguente:

/**
 * 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;
}
Argomento facoltativo in un tipo di funzione {function(?string=, number=)}
Una funzione che accetta come stringa facoltativa e un numero facoltativo come argomenti.
Indica che un argomento in un tipo di funzione è facoltativo. Un argomento facoltativo può essere omesso dalla chiamata della funzione. Un argomento facoltativo non può precedere un argomento non facoltativo nell'elenco di argomenti.
Il tipo ALL {*} Indica che la variabile può assumere qualsiasi tipo.
Il tipo UNKNOWN {?} Indica che la variabile può assumere qualsiasi tipo e che il compilatore non deve eseguire controlli di digitazione per qualsiasi utilizzo.

Tipo di trasmissione

Per trasmettere un valore a un tipo specifico, utilizza questa sintassi

/** @type {!MyType} */ (valueExpression)
Le parentesi attorno all'espressione sono sempre obbligatorie.

Tipi generici

Proprio come Java, il componente Closure Compiler supporta tipi, funzioni e metodi generici. I generici utilizzano oggetti di diversi tipi preservando la sicurezza dei tipi di tempo.

Puoi utilizzare i generici per implementare raccolte generalizzate che contengono riferimenti a oggetti di un certo tipo e algoritmi generalizzati che operano su oggetti di un certo tipo.

Dichiarazione di un tipo generico

Un tipo può essere reso generico aggiungendo un'annotazione @template al costruttore del tipo (per le classi) o alla dichiarazione dell'interfaccia (per le interfacce). Ad esempio:

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

L'annotazione @template T indica che Foo è un tipo generico con un tipo di modello T. È possibile utilizzare il tipo di modello T come tipo nell'ambito della definizione di Foo. Ad esempio:

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

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

Il metodo get restituirà un oggetto di tipo T e il metodo set accetterà solo oggetti di tipo T.

Creazione dell'istanza di un tipo generico

Riutilizzando l'esempio precedente, puoi creare un'istanza modello di Foo in diversi modi:

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

Entrambe le istruzioni del costruttore precedenti creano un'istanza Foo il cui modello T è string. Il compilatore impone che le chiamate ai metodi di foo e l'accesso alle proprietà di foo rispettano il tipo basato su modello. Ad esempio:

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

Le istanze possono anche essere implicite digitate dai rispettivi argomenti costruttori. Considera un tipo generico diverso, Bar:

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

Il tipo di argomento del costruttore Bar viene dedotto come string, pertanto l'istanza creata bar viene dedotta come Bar<string>.

Più tipi di modello

Un generico può avere un numero qualsiasi di tipi di modello. La seguente classe di mappa ha due tipi di modello:

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

Tutti i tipi di modello per un tipo generico devono essere specificati nella stessa annotazione @template di un elenco separato da virgole. L'ordine dei nomi dei tipi di modello è importante, poiché le annotazioni dei tipi basati su modelli utilizzeranno l'ordine per abbinare i tipi di modello ai valori. Ad esempio:

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

Invarianza di tipi generici

Il compilatore Closure applica la digitazione generica invariante. Ciò significa che se un contesto prevede un tipo Foo<X>, non puoi passare un tipo Foo<Y> quando X e Y sono tipi diversi, anche se uno è un sottotipo dell'altro. Ad esempio:

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

Ereditarietà dei tipi generici

I tipi generici possono essere ereditati e i loro tipi di modello possono essere fissi o propagati al tipo ereditato. Di seguito è riportato un esempio di un tipo ereditato che corregge il tipo di modello del relativo supertipo:

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

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

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

Se estendi A<string>, B avrà un metodo method che accetta un parametro di tipo string.

Ecco un esempio di un tipo ereditato che propaga il tipo di modello del suo supertipo:

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

L'estensione di A<U> alle istanze modello di C avrà un metodo method che accetta un parametro del tipo modello U.

Le interfacce possono essere implementate ed estese in modo simile, ma un singolo tipo non può implementare la stessa interfaccia più volte con tipi di modelli diversi. Ad esempio:

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

Funzioni e metodi generici

In modo simile a quelle generiche, le funzioni e i metodi possono essere resi generici aggiungendo un'annotazione @template alla relativa definizione. Ad esempio:

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