Nota: Esta página está desactualizada. La lista completa se mantiene en https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler
Descripción general
Closure Compiler puede usar la información de tipo de datos sobre las variables de JavaScript para proporcionar advertencias y optimizaciones mejoradas. Sin embargo, JavaScript no tiene forma de declarar tipos.
Debido a que JavaScript no tiene sintaxis para declarar el tipo de una variable, debes usar comentarios en el código a fin de especificar el tipo de datos.
El lenguaje de tipo de Closure Compiler se deriva de las anotaciones que usa la herramienta de generación de documentos JSDoc, aunque ha cambiado. Ahora incluye varias anotaciones que JSDoc no admite, y viceversa. En este documento, se describe el conjunto de anotaciones y expresiones de tipo que comprende Closure Compiler.
Etiquetas de JSDoc
El Closure Compiler busca información de tipo en etiquetas JSDoc. Usa las etiquetas JSDoc que se describen en la tabla de referencia a continuación para ayudar al compilador a optimizar tu código y verificar si es posible encontrar errores de tipo y otros errores.
En esta tabla, se incluyen solo las etiquetas que afectan el comportamiento del Closure Compiler. Para obtener información acerca de otras etiquetas JSDoc, consulta la documentación del kit de herramientas de JSDoc.
Etiqueta | Descripción |
---|---|
@abstract
|
Marca un método como abstracto. De manera similar a la configuración de un método en
El compilador genera una advertencia si un método marcado con /** @abstract */ foo.MyClass.prototype.abstractMethod = function() {}; |
@const
|
Marca una variable como de solo lectura. El compilador puede intercalar variables La declaración de tipo es opcional.
El compilador genera una advertencia si a una variable marcada 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
|
Marca una función como constructor.
El compilador requiere una anotación Por ejemplo: /** * A rectangle. * @constructor */ function GM_Rect() { ... } |
@define
|
Indica una constante que el compilador puede anular en el tiempo de compilación.
Con el ejemplo de la izquierda, puedes pasar la marca --define='ENABLE_DEBUG=false' al compilador para cambiar el valor de ENABLE_DEBUG a false.
El tipo de una constante definida puede ser un número, una string o un valor booleano.
Las definiciones solo se permiten en el alcance global.
Por ejemplo: /** @define {boolean} */ var ENABLE_DEBUG = true; /** @define {boolean} */ goog.userAgent.ASSUME_IE = false; |
@deprecated
|
Marca una función, un método o una propiedad de modo que, cuando se use, se genere una advertencia del compilador que indica que ya no debe usarse. Por ejemplo: /** * 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
|
Por ejemplo: /** * @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
|
Especifica el tipo de enumeración. Una enumeración es un objeto cuyas propiedades constituyen un conjunto de constantes relacionadas. La etiqueta La etiqueta de tipo de una enumeración se aplica a cada propiedad de la enumeración. Por ejemplo, si una enumeración tiene el tipo Por ejemplo: /** * Enum for tri-state values. * @enum {number} */ project.TriState = { TRUE: 1, FALSE: -1, MAYBE: 0 }; |
@export
|
Dado este código /** @export */ foo.MyPublicClass.prototype.myPublicMethod = function() { // ... };
cuando el compilador se ejecute con la marca goog.exportProperty(foo.MyPublicClass.prototype, 'myPublicMethod', foo.MyPublicClass.prototype.myPublicMethod); que exportará los símbolos a código sin compilar. Puedes escribir /** * @export * @type {SomeType} */. El código que usa la anotación
|
@extends
|
Marca una clase o interfaz como heredada de otra clase. Una clase marcada con
Nota:
Para ver una implementación de herencia de ejemplo, consulta la función de biblioteca de cierre Por ejemplo: /** * Immutable empty node list. * @constructor * @extends {goog.ds.BasicNodeList} */ goog.ds.EmptyNodeList = function() { ... }; |
@final
|
Indica que no se puede extender esta clase. Para los métodos, indica que ninguna subclase puede anular ese método. Por ejemplo: /** * A class that cannot be extended. * @final * @constructor */ sloth.MyFinalClass = function() { ... } /** * A method that cannot be overridden. * @final */ sloth.MyFinalClass.prototype.method = function() { ... }; |
@implements
|
Se usa con
El compilador genera una advertencia si etiquetas un constructor con Por ejemplo: /** * A shape. * @interface */ function Shape() {}; Shape.prototype.draw = function() {}; /** * @constructor * @implements {Shape} */ function Square() {}; Square.prototype.draw = function() { ... }; |
@implicitCast
|
Esta anotación solo puede aparecer en declaraciones de propiedad de externs.
La propiedad tiene un tipo declarado, pero puedes asignarle cualquier tipo sin advertencia. Cuando accedes a la propiedad, obtienes un valor del tipo declarado. Por ejemplo, a /** * @type {string} * @implicitCast */ Element.prototype.innerHTML; |
@inheritDoc
|
Indica que un método o una propiedad de una subclase oculta intencionalmente un método o una propiedad de la superclase, y tiene exactamente la misma documentación. Ten en cuenta que la etiqueta Por ejemplo: /** @inheritDoc */ project.SubClass.prototype.toString = function() { ... }; |
@interface
|
Marca una función como una interfaz. Una interfaz especifica los miembros necesarios de un tipo. Cualquier clase que implemente una interfaz debe implementar todos los métodos y las propiedades definidas en el prototipo de la interfaz. Consulta
El compilador verifica que no se creen instancias de interfaces. Si se usa la palabra clave Por ejemplo: /** * A shape. * @interface */ function Shape() {}; Shape.prototype.draw = function() {}; /** * A polygon. * @interface * @extends {Shape} */ function Polygon() {}; Polygon.prototype.getSides = function() {}; |
@lends
|
Indica que las claves de un literal de objeto se deben tratar como propiedades de otro objeto. Esta anotación solo debería aparecer en los literales de objeto.
Ten en cuenta que el nombre entre llaves no es un nombre de tipo como en otras anotaciones. Es un nombre de objeto. Nombra el objeto al que se le prestan las propiedades.
Por ejemplo, En los documentos de JSDoc Toolkit, encontrarás más información sobre esta anotación. Por ejemplo: goog.object.extend( Button.prototype, /** @lends {Button.prototype} */ ({ isButton: function() { return true; } })); |
@license o @preserve
|
Indica al compilador que inserte el comentario asociado antes del código compilado para el archivo marcado. Esta anotación permite que los avisos importantes (como licencias legales o texto de derechos de autor) sobrevivan a la compilación sin cambios. Los saltos de línea se conservan. Por ejemplo: /** * @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
|
Denota una propiedad que el compilador no debe contraer en una variable. El uso principal de Por ejemplo: /** * A namespace. * @const */ var foo = {}; /** * @nocollapse */ foo.bar = 42; window['foobar'] = foo.bar; |
@nosideeffects
|
Indica que una llamada a la función externa declarada no tiene efectos secundarios.
Esta anotación permite que el compilador quite llamadas a la función si no se usa el valor que se muestra. La anotación solo se permite en Por ejemplo: /** @nosideeffects */ function noSideEffectsFn1() {} /** @nosideeffects */ var noSideEffectsFn2 = function() {}; /** @nosideeffects */ a.prototype.noSideEffectsFn3 = function() {}; |
@override
|
Indica que un método o una propiedad de una subclase oculta de manera intencional un método o la propiedad de la superclase. Si no se incluyen otras anotaciones, el método o la propiedad hereda automáticamente las anotaciones de su superclase. Por ejemplo: /** * @return {string} Human-readable representation of * project.SubClass. * @override */ project.SubClass.prototype.toString = function() { ... }; |
@package
|
Marca un miembro o una propiedad como un paquete privado. Solo el código en el mismo directorio puede acceder a los nombres marcados como
Los constructores públicos pueden tener propiedades Por ejemplo: /** * 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
|
Se usa con definiciones de método, función y constructor para especificar los tipos de argumentos de funciones. Las etiquetas
La etiqueta
Como alternativa, puedes anotar los tipos de parámetros intercalados (consulta la función Por ejemplo: /** * 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; }Para los parámetros que son un patrón de desestructuración, puedes usar cualquier nombre que sea un identificador de JS válido, después de la anotación de tipo. /** * @param {{name: string, age: number}} person */ function logPerson({name, age}) { console.log(`${name} is ${age} years old`); } |
@private
|
Marca un miembro como privado. Solo el código del mismo archivo puede acceder a las variables y funciones globales marcadas como
También se puede acceder a las propiedades estáticas públicas de los constructores marcados con Por ejemplo: /** * Handlers that are listening to this logger. * @private {Array<Function>} */ this.handlers_ = []; |
@protected
|
Indica que un miembro o una propiedad está protegida.
Una propiedad marcada como
Por ejemplo: /** * 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
|
Marca una función como una interfaz estructural. Una interfaz estructural es similar a una Por ejemplo: /** * 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
|
Especifica los tipos de datos que se muestran de las definiciones de métodos y funciones.
La etiqueta
Como alternativa, puedes anotar el tipo de datos que se muestra intercalado (consulta la función
Si una función que no está en elementos externos no tiene un valor para mostrar, puedes omitir la etiqueta Por ejemplo: /** * 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
|
Por ejemplo: /** * @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
|
Consulta Tipos genéricos. Por ejemplo: /** * @param {T} t * @constructor * @template T */ Container = function(t) { ... }; |
@this
|
Especifica el tipo de objeto al que hace referencia la palabra clave
Para evitar las advertencias del compilador, debes usar una anotación Por ejemplo: chat.RosterWidget.extern('getRosterElement', /** * Returns the roster widget element. * @this {Widget} * @return {Element} */ function() { return this.getComponent().getElement(); }); |
@throws
|
Se usa para documentar las excepciones que arroja una función. El verificador de tipos no usa esta información actualmente. Solo se usa para determinar si una función declarada en un archivo externo tiene efectos secundarios. Por ejemplo: /** * @throws {DOMException} */ DOMApplicationCache.prototype.swapCache = function() { ... }; |
@type
|
Identifica el tipo de una variable, una propiedad o una expresión. La etiqueta Cuando se declara una variable o un parámetro de función, puedes escribir la anotación de tipo intercalada y omitir Por ejemplo: /** * The message hex ID. * @type {string} */ var hexId = hexId; var /** string */ name = 'Jamie'; function useSomething(/** (string|number|!Object) */ something) { ... } |
@typedef
|
Declara un alias para un tipo más complejo. Actualmente, typedefs solo se puede definir en el nivel superior, no dentro de funciones. Corregimos esta limitación en la inferencia de tipo nueva. Por ejemplo: /** @typedef {(string|number)} */ goog.NumberLike; /** @param {goog.NumberLike} x A number or a string. */ goog.readNumber = function(x) { ... } |
@unrestricted
|
Indica que una clase no es un tipo Por ejemplo: /** * @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 |
Expresiones de tipo
Puedes especificar el tipo de datos de cualquier variable, propiedad, expresión o parámetro de función con una expresión de tipo. Una expresión de tipo consta de llaves (“{ }") que contienen alguna combinación de los operadores de tipo descritos a continuación.
Usa una expresión de tipo con la etiqueta @param
para declarar el tipo de un parámetro de función. Usa una expresión de tipo con la etiqueta @type
para declarar el tipo de una variable, una propiedad o una expresión.
Cuantos más tipos especifiques en tu código, más optimizaciones podrá realizar el compilador y más errores podrá detectar.
El compilador usa estas anotaciones para comprobar el tipo de programa.
Ten en cuenta que Closure Compiler no realiza ninguna promesa de que podrá determinar el tipo de cada expresión de tu programa. Hace su mejor esfuerzo observando cómo se usan las variables y las anotaciones de tipo adjuntas a sus declaraciones. Luego, utiliza varios algoritmos de inferencia de tipo para determinar el tipo de la mayor cantidad posible de expresiones. Algunos de estos algoritmos son directos ("si x es un número y vemos y = x;
, entonces y es un número"). Algunos son más indirectos ("si el primer parámetro de f está documentado como una devolución de llamada que debe tomar un número, y vemos f(function(x) { /** ... */ });
, entonces x debe ser un número").
Nombre de operador | Ejemplos de sintaxis | Descripción |
---|---|---|
Nombre del tipo |
{boolean} {Window} {goog.ui.Menu}
|
Especifica el nombre de un tipo. |
Tipo de aplicación |
{Array<string>} Un arreglo de strings.
|
Parametriza un tipo con un conjunto de argumentos de tipo. Similar a los genéricos de Java. |
Tipo: unión |
{(number|boolean)} Es un número o un valor booleano. Ten en cuenta los paréntesis, que son obligatorios. |
Indica que un valor puede tener el tipo A O tipo B. |
Tipo de registro |
{{myNum: number, myObject}} Es un tipo anónimo con una propiedad llamada myNum que tiene un valor de tipo number y una propiedad llamada myObject que tiene un valor de cualquier tipo.
|
Indica que el valor tiene los miembros especificados con valores de los tipos especificados. Las llaves forman parte de la sintaxis de tipo. Por ejemplo, para denotar un |
Tipo anulable |
{?number} Un número o null .
|
Indica que un valor es de tipo A o Todos los tipos de objetos son anulables de forma predeterminada, ya sea que estén declarados con el operador Null o no. Un tipo de objeto se define como cualquier cosa, excepto una función, una string, un número o un valor booleano. Para hacer que un tipo de objeto sea no anulable, usa el operador No anulable. |
Tipo no anulable |
{!Object} Es un objeto, pero nunca el valor null .
|
Indica que un valor es de tipo A y no es nulo. Las funciones y todos los tipos de valores (booleano, número y string) no son anulables de forma predeterminada, ya sea que estén declarados con el operador no anulable o no. Para hacer que un valor o un tipo de función sea anulable, usa el operador Nullable. |
Tipo de función |
{function(string, boolean)} Una función que toma dos parámetros (una string y un valor booleano) y tiene un valor de retorno desconocido. |
Especifica una función y los tipos de parámetros de la función. |
Tipo de datos que se muestra de la función |
{function(): number} Es una función que no toma parámetros y muestra un número. |
Especifica el tipo de valor que se muestra de una función. |
Tipo de función this |
{function(this:goog.ui.Menu, string)} Es una función que toma un parámetro (una string) y se ejecuta en el contexto de un goog.ui. |
Especifica el tipo de valor de this dentro de la función. |
Tipo de función new |
{function(new:goog.ui.Menu, string)} Es una función que toma un parámetro (una string) y crea una instancia nueva de goog.ui.Menu cuando se llama con la palabra clave "new". |
Especifica el tipo construido de un constructor. |
Parámetros variables |
{function(string, ...number): number} Una función que toma un parámetro (una string) y, luego, una cantidad variable de parámetros que deben ser números. |
Indica que un tipo de función toma una cantidad variable de parámetros y especifica un tipo de parámetros. |
Parámetros variables (en anotaciones @param )
|
@param {...number} var_args Cantidad variable de parámetros para una función anotada. |
Indica que la función anotada acepta una cantidad variable de parámetros y especifica un tipo para los parámetros variables. |
Parámetro opcional en una anotación @param
|
@param {number=} opt_argument Un parámetro opcional del tipo number .
|
Indica que el argumento descrito por una anotación
Si una llamada de método omite un parámetro opcional, ese argumento tendrá un valor de /** * 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; } |
Argumento opcional en un tipo de función |
{function(?string=, number=)} Una función que toma una string opcional anulable y un número opcional como argumentos. |
Indica que un argumento en un tipo de función es opcional. Se puede omitir un argumento opcional de la llamada a función. Un argumento opcional no puede preceder a un argumento no opcional en la lista de argumentos. |
El tipo TODO | {*} |
Indica que la variable puede adoptar cualquier tipo. |
El tipo UNKNOWN | {?} |
Indica que la variable puede tomar cualquier tipo, y el compilador no debe verificar ningún uso de la misma. |
Conversión de tipos
Para convertir un valor en un tipo específico, usa esta sintaxis
/** @type {!MyType} */ (valueExpression)Los paréntesis alrededor de la expresión siempre son obligatorios.
Tipos genéricos
Al igual que Java, el compilador de Closure admite tipos, funciones y métodos genéricos. Los genéricos operan en objetos de varios tipos y conservan la seguridad de tipo en tiempo de compilación.
Puedes usar elementos genéricos para implementar colecciones generalizadas que tengan referencias a objetos de un tipo determinado y algoritmos generalizados que operen sobre objetos de un tipo determinado.
Declaración de un tipo genérico
Un tipo se puede hacer genérico agregando una anotación @template
al constructor del tipo (para clases) o la declaración de la interfaz (para las interfaces). Por ejemplo:
/** * @constructor * @template T */ Foo = function() { ... };
La anotación @template T
indica que Foo
es un tipo genérico con un tipo de plantilla, T
.
El tipo de plantilla T
se puede usar como un tipo dentro del alcance de la definición de Foo
. Por ejemplo:
/** @return {T} */ Foo.prototype.get = function() { ... }; /** @param {T} t */ Foo.prototype.set = function(t) { ... };
El método get
mostrará un objeto de tipo T
, y el método set
solo aceptará objetos de tipo T
.
Crea una instancia de un tipo genérico
Si reutilizas el ejemplo anterior, se puede crear una instancia con plantilla de Foo
de varias maneras:
/** @type {!Foo<string>} */ var foo = new Foo(); var foo = /** @type {!Foo<string>} */ (new Foo());
Las dos instrucciones de constructor anteriores crean una instancia Foo
cuyo tipo de plantilla T
es string
. El compilador aplicará esa llamada a los métodos de foo
y accederá a las propiedades de foo
, respetará el tipo de plantilla. Por ejemplo:
foo.set("hello"); // OK. foo.set(3); // Error - expected a string, found a number. var x = foo.get(); // x is a string.
Las instancias también se pueden escribir de forma implícita con sus argumentos de constructor.
Considera un tipo genérico diferente, Bar
:
/** * @param {T} t * @constructor * @template T */ Bar = function(t) { ... }; var bar = new Bar("hello"); // bar is a Bar<string>
El tipo del argumento para el constructor Bar
se infiere como string
y, como resultado, la instancia creada bar
se infiere como Bar<string>
.
Varios tipos de plantillas
Un genérico puede tener cualquier cantidad de tipos de plantillas. La siguiente clase de mapa tiene dos tipos de plantillas:
/** * @constructor * @template Key, Val */ MyMap = function() { ... };
Todos los tipos de plantilla para un tipo genérico deben especificarse en la misma anotación @template
, como una lista separada por comas. El orden de los nombres de los tipos de plantilla es importante, ya que las anotaciones de tipo de plantilla usarán el orden para sincronizar los tipos de plantilla con los valores. Por ejemplo:
/** @type {MyMap<string, number>} */ var map; // Key = string, Val = number.
Invariancia de tipos genéricos
El Closure Compiler aplica la escritura genérica invariable. Esto significa que si un contexto espera un tipo Foo<X>
, no puedes pasar un tipo Foo<Y>
cuando X
y Y
son tipos diferentes, incluso si uno es un subtipo del otro. Por ejemplo:
/** * @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
Herencia de tipos genéricos
Los tipos genéricos se pueden heredar y sus tipos de plantillas se pueden corregir o propagar al tipo heredado. A continuación, se muestra un ejemplo de un tipo heredado que corrige el tipo de plantilla de su supertipo:
/** * @constructor * @template T */ A = function() { ... }; /** @param {T} t */ A.prototype.method = function(t) { ... }; /** * @constructor * @extends {A<string>} */ B = function() { ... };
Si extiendes A<string>
, B
tendrá un método method
que tome un parámetro de tipo string
.
Este es un ejemplo de un tipo heredado que propaga el tipo de plantilla de su supertipo:
/** * @constructor * @template U * @extends {A<U>} */ C = function() { ... };
Si extiendes A<U>
, las instancias con plantilla de C
tendrán un método method
que tome un parámetro del tipo de plantilla U
.
Las interfaces se pueden implementar y extender de manera similar, pero un solo tipo no puede implementar la misma interfaz varias veces con diferentes tipos de plantillas. Por ejemplo:
/** * @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
Funciones y métodos genéricos
Al igual que los tipos genéricos, las funciones y los métodos pueden hacerse genéricos si agregas una anotación @template
a su definición. Por ejemplo:
/** * @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