Nota: questa pagina è obsoleta. L'elenco completo è disponibile all'indirizzo https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler
Panoramica
Closure Compiler può utilizzare le informazioni sul tipo di dati delle variabili JavaScript per fornire avvisi e ottimizzazioni avanzate. JavaScript, tuttavia, non ha modo di dichiarare i tipi.
Poiché JavaScript non ha una sintassi per dichiarare il tipo di una variabile, devi utilizzare i commenti nel codice per specificare il tipo di dati.
Il linguaggio dei tipi di Closure Compiler deriva dalle annotazioni utilizzate dallo strumento di generazione della documentazione JSDoc, anche se da allora è cambiato. Ora include diverse annotazioni che JSDoc non supporta e viceversa. Questo documento descrive l'insieme di annotazioni ed espressioni di tipo che Closure Compiler comprende.
Tag JSDoc
Closure Compiler cerca le informazioni sui tipi nei tag JSDoc. Utilizza i tag JSDoc descritti nella tabella di riferimento riportata di seguito per aiutare il compilatore a ottimizzare il codice e a verificare la presenza di possibili errori di tipo e altri errori.
Questa tabella include solo i tag che influiscono sul comportamento del compilatore Closure. Per informazioni su altri tag JSDoc, consulta la documentazione di JSDoc Toolkit.
Tag | Descrizione |
---|---|
@abstract
|
Contrassegna un metodo come astratto. Analogamente all'impostazione di un metodo su
Il compilatore genera un avviso se un metodo contrassegnato
con /** @abstract */ foo.MyClass.prototype.abstractMethod = function() {}; |
@const
|
Contrassegna una variabile come di sola lettura. Il compilatore può
incorporare le variabili La dichiarazione del tipo è facoltativa.
Il compilatore genera un avviso se a una variabile contrassegnata
con /** @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 Ad esempio: /** * A rectangle. * @constructor */ function GM_Rect() { ... } |
@define
|
Indica una costante che può essere sostituita dal compilatore in fase di compilazione.
Con l'esempio a sinistra, puoi passare il flag
--define='ENABLE_DEBUG=false'
al compilatore per modificare il valore di
ENABLE_DEBUG in false.
Il tipo di una costante definita può essere numerico, stringa o 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à in modo che il relativo utilizzo generi un avviso del compilatore che indica che non deve più essere utilizzata. 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
|
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 L'etichetta del tipo di un'enumerazione si applica a ogni proprietà dell'enumerazione. Ad esempio, se un'enumerazione ha il tipo 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 goog.exportProperty(foo.MyPublicClass.prototype, 'myPublicMethod', foo.MyPublicClass.prototype.myPublicMethod); che esporterà i simboli nel codice non compilato. Puoi scrivere
/** * @export * @type {SomeType} */ Il codice che utilizza l'annotazione
|
@extends
|
Contrassegna una classe o un'interfaccia come ereditata da un'altra classe. Una classe
contrassegnata con
Nota:
Per un esempio di implementazione dell'ereditarietà, consulta
la funzione Ad esempio: /** * Immutable empty node list. * @constructor * @extends {goog.ds.BasicNodeList} */ goog.ds.EmptyNodeList = function() { ... }; |
@final
|
Indica che questo corso non può essere esteso. Per i metodi, indica che nessuna sottoclasse può eseguire l'override di 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
Il compilatore genera un avviso se contrassegni un costruttore
con Ad esempio: /** * A shape. * @interface */ function Shape() {}; Shape.prototype.draw = function() {}; /** * @constructor * @implements {Shape} */ function Square() {}; Square.prototype.draw = function() { ... }; |
@implicitCast
|
Questa annotazione può essere visualizzata solo nelle dichiarazioni di proprietà esterne.
La proprietà ha un tipo dichiarato, ma puoi assegnarle qualsiasi tipo senza
ricevere un avviso. Quando accedi alla proprietà, ricevi
un valore del tipo dichiarato. Ad esempio,
/** * @type {string} * @implicitCast */ Element.prototype.innerHTML; |
@inheritDoc
|
Indica che un metodo o una proprietà di una sottoclasse
nasconde intenzionalmente un metodo o una proprietà della superclasse e ha
esattamente la stessa documentazione. Tieni presente che
il tag 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. Vedi
Il compilatore verifica che le interfacce non vengano istanziate. Se
la parola chiave 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 di un oggetto letterale devono essere trattate come proprietà di un altro oggetto. Questa annotazione deve essere visualizzata solo nei valori letterali oggetto.
Tieni presente che il nome tra parentesi graffe non è un nome di tipo come
in altre annotazioni. È il nome di un oggetto. Indica
l'oggetto a cui vengono prestate le proprietà.
Ad esempio, La documentazione del toolkit JSDoc contiene ulteriori informazioni su questa annotazione. 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 note importanti (come licenze legali o testo del copyright) durante la compilazione. Le interruzioni di riga vengono mantenute. 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 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
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à eredita automaticamente le annotazioni dalla 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 privato del pacchetto. Solo il codice nella stessa directory
può accedere ai nomi contrassegnati con
I costruttori pubblici possono avere 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 definizioni di metodi, funzioni e costruttori per specificare
i tipi di argomenti della funzione. I tag
Il tag
In alternativa, puoi annotare i tipi di parametri in linea
(vedi la funzione 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; } /** * @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
a variabili e funzioni globali
contrassegnate con
È possibile accedere ovunque anche alle proprietà statiche pubbliche dei costruttori contrassegnati con Ad esempio: /** * Handlers that are listening to this logger. * @private {Array<Function>} */ this.handlers_ = []; |
@protected
|
Indica che un membro o una proprietà è protetto.
Una proprietà contrassegnata con
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 un tipo nominale 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 restituiti delle definizioni di metodi e funzioni.
Il tag
In alternativa, puoi annotare il tipo restituito inline
(vedi la funzione
Se una funzione che non è in externs non ha un valore restituito, puoi omettere il tag
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
|
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
Per evitare avvisi del compilatore, devi utilizzare
un'annotazione 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. Il controllo dei tipi non utilizza attualmente queste informazioni. Viene utilizzato solo per capire se una funzione dichiarata in un file externs ha effetti collaterali. Ad esempio: /** * @throws {DOMException} */ DOMApplicationCache.prototype.swapCache = function() { ... }; |
@type
|
Identifica il tipo di variabile, proprietà o espressione. Il tag Quando dichiari una variabile o un parametro di funzione,
puoi scrivere l'annotazione di tipo in linea omettendo
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, i typedef possono essere definiti solo a livello principale, non all'interno delle funzioni. Abbiamo corretto questa limitazione nella nuova inferenza dei tipi. Ad esempio: /** @typedef {(string|number)} */ goog.NumberLike; /** @param {goog.NumberLike} x A number or a string. */ goog.readNumber = function(x) { ... } |
@unrestricted
|
Indica che un corso non è di tipo 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 |
Espressioni di tipo
Puoi specificare il tipo di dati di qualsiasi variabile, proprietà, espressione o parametro di funzione con un'espressione di tipo. Un'espressione di tipo è costituita da parentesi graffe ("{ }") contenenti una combinazione degli operatori di tipo descritti di seguito.
Utilizza un'espressione di tipo con
il tag @param
per dichiarare il
tipo di un parametro di funzione. Utilizza un'espressione di tipo con
il tag @type
per dichiarare il
tipo di una variabile, una proprietà o un'espressione.
Più tipi specifichi nel codice, più ottimizzazioni può apportare il compilatore e più errori può rilevare.
Il compilatore utilizza queste annotazioni per controllare il tipo del programma.
Tieni presente che Closure Compiler non garantisce di poter determinare il tipo di ogni espressione nel tuo programma. Fa del suo meglio esaminando il modo in cui vengono utilizzate le variabili e le annotazioni di tipo associate alle relative dichiarazioni. Poi, utilizza una serie di algoritmi di inferenza dei tipi per
determinare il tipo di quante più espressioni possibili. 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's
è documentato come callback che deve accettare un numero
e vediamo f(function(x) { /** ... */ });
, allora x deve essere
un numero").
Nome operatore | Esempi di sintassi | Descrizione |
---|---|---|
Digita nome |
{boolean} {Window} {goog.ui.Menu}
|
Specifica il nome di un tipo. |
Type Application |
{Array<string>} Un array di stringhe.
|
Parametrizza un tipo con un insieme di argomenti di tipo. Simile ai generici Java. |
Type Union |
{(number|boolean)} Un numero o un valore booleano. Nota le parentesi, che sono obbligatorie. |
Indica che un valore potrebbe essere di tipo A O di tipo B. |
Tipo di record |
{{myNum: number, myObject}}
Un tipo anonimo con una proprietà denominata myNum
con un valore di tipo number e una proprietà
denominata myObject con un valore di qualsiasi tipo.
|
Indica che il valore ha i membri specificati con valori dei tipi specificati. Le parentesi graffe fanno parte della sintassi del tipo. Ad esempio, per
indicare un |
Tipo nullable |
{?number} Un numero o null .
|
Indica che un valore è di tipo A o Per impostazione predefinita, tutti i tipi di oggetti sono annullabili, indipendentemente dal fatto che siano dichiarati con l'operatore Nullable. Un tipo di oggetto è definito come qualsiasi cosa tranne una funzione, una stringa, un numero o un valore booleano. Per rendere un tipo di oggetto non annullabile, utilizza l'operatore Non annullabile. |
Tipo non annullabile |
{!Object} Un oggetto, ma mai il valore null .
|
Indica che un valore è di tipo A e non nullo. Per impostazione predefinita, le funzioni e tutti i tipi di valori (booleano, numerico e stringa) non sono annullabili, indipendentemente dal fatto che siano dichiarati o meno con l'operatore Non-nullable. Per rendere annullabile un tipo di valore o 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 di parametri della funzione. |
Tipo restituito della funzione |
{function(): number} Una funzione che non accetta parametri e restituisce un numero. |
Specifica il tipo di valore restituito di una funzione. |
Tipo di funzione this |
{function(this:goog.ui.Menu, string)} Una funzione che accetta un parametro (una stringa) ed esegue nel contesto di goog.ui.Menu. |
Specifica il tipo di 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 poi 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 variabili. |
Parametri variabili (nelle annotazioni @param )
|
@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 variabili. |
Parametro facoltativo in un'annotazione @param
|
@param {number=} opt_argument Un parametro facoltativo di tipo number .
|
Indica che l'argomento descritto da
un'annotazione
Se una chiamata al metodo omette un parametro facoltativo, l'argomento avrà
un valore di /** * 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 una stringa facoltativa e nullabile e un numero facoltativo come argomenti. |
Indica che un argomento in un tipo di funzione è facoltativo. Un argomento facoltativo può essere omesso dalla chiamata alla funzione. Un argomento facoltativo non può precedere un argomento non facoltativo nell'elenco degli argomenti. |
Il tipo ALL | {*} |
Indica che la variabile può assumere qualsiasi tipo. |
Tipo UNKNOWN | {?} |
Indica che la variabile può assumere qualsiasi tipo e che il compilatore non deve eseguire il controllo del tipo per nessuno dei suoi utilizzi. |
Type Casting
Per eseguire il cast di un valore in un tipo specifico, utilizza questa sintassi
/** @type {!MyType} */ (valueExpression)
Tipi generici
Proprio come Java, Closure Compiler supporta tipi, funzioni e metodi generici. I generici operano su oggetti di vari tipi preservando la sicurezza dei tipi in fase di compilazione.
Puoi utilizzare i generici per implementare raccolte generalizzate che contengono riferimenti a oggetti di un tipo specifico e algoritmi generalizzati che operano su oggetti di un tipo specifico.
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
.
Il tipo di modello T
può essere utilizzato 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
,
mentre il metodo set
accetterà solo oggetti di tipo T
.
Creazione di un'istanza di un tipo generico
Se riutilizziamo l'esempio precedente, è possibile creare un'istanza basata su 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 tipo di modello T
è string
. Il compilatore
impone che le chiamate ai metodi di foo
e gli accessi alle
proprietà di foo
rispettino 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 digitate implicitamente dagli argomenti del costruttore.
Prendi in considerazione un altro tipo generico, Bar
:
/** * @param {T} t * @constructor * @template T */ Bar = function(t) { ... }; var bar = new Bar("hello"); // bar is a Bar<string>
Il tipo dell'argomento del costruttore Bar
viene dedotto
come string
e, di conseguenza, l'istanza creata
bar
viene dedotta come Bar<string>
.
Più tipi di modello
Un generico può avere un numero qualsiasi di tipi di modelli. La seguente classe di mappe ha due tipi di modello:
/** * @constructor * @template Key, Val */ MyMap = function() { ... };
Tutti i tipi di modelli per un tipo generico devono essere specificati nella stessa annotazione @template
, come elenco separato da virgole. L'ordine dei nomi dei tipi di modelli è importante, poiché le annotazioni dei tipi di modelli utilizzeranno l'ordine per accoppiare i tipi di modelli con i valori. Ad esempio:
/** @type {MyMap<string, number>} */ var map; // Key = string, Val = number.
Invarianza dei tipi generici
Closure Compiler 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
Eredità dei tipi generici
I tipi generici possono essere ereditati e i relativi tipi di modelli possono essere fissi o propagati al tipo ereditato. Ecco 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() { ... };
Estendendo 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() { ... };
Estendendo A<U>
, le istanze basate su modelli di C
avranno un metodo method
che accetta un parametro del tipo di 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
Analogamente ai tipi generici, le funzioni e i metodi possono essere resi generici aggiungendo
un'annotazione @template
alla loro 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