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
El compilador de cierre puede usar información sobre el tipo de datos de las variables de JavaScript para proporcionar optimizaciones y advertencias mejoradas. Sin embargo, JavaScript no tiene forma de declarar tipos.
Como JavaScript no tiene sintaxis para declarar el tipo de una variable, debes usar comentarios en el código para especificar el tipo de datos.
El lenguaje de tipos del compilador de Closure se deriva de las anotaciones que usa la herramienta de generación de documentos JSDoc, aunque desde entonces se ha diferenciado. 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 el compilador de Closure.
Etiquetas de JSDoc
El compilador de Closure busca información de tipos en las etiquetas de JSDoc. Usa las etiquetas JSDoc que se describen en la siguiente tabla de referencia para ayudar al compilador a optimizar tu código y verificar si hay posibles errores de tipo y otros errores.
Esta tabla solo incluye las etiquetas que afectan el comportamiento del compilador de cierre. Para obtener información sobre otras etiquetas de JSDoc, consulta la documentación del kit de herramientas de JSDoc.
Etiqueta | Descripción |
---|---|
@abstract
|
Marca un método como abstracto. Al igual que cuando se configura un método como
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 insertar 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 momento de la 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 cadena 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 para que su uso genere una advertencia del compilador que indique que ya no se debe usar. 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. Un enum es un objeto cuyas propiedades constituyen un conjunto de constantes relacionadas. La etiqueta La etiqueta de tipo de un enum se aplica a cada propiedad del enum. Por ejemplo, si un enum 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 se ejecuta el compilador con la marca goog.exportProperty(foo.MyPublicClass.prototype, 'myPublicMethod', foo.MyPublicClass.prototype.myPublicMethod); que exportará los símbolos al 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 un ejemplo de implementación de herencia, consulta la función de la biblioteca de Closure Por ejemplo: /** * Immutable empty node list. * @constructor * @extends {goog.ds.BasicNodeList} */ goog.ds.EmptyNodeList = function() { ... }; |
@final
|
Indica que no se permite extender esta clase. En el caso de 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 propiedades externas.
La propiedad tiene un tipo declarado, pero puedes asignarle cualquier tipo sin una 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 requeridos de un tipo. Cualquier clase que implemente una interfaz debe implementar todos los métodos y las propiedades definidos en el prototipo de la interfaz. Consulta
El compilador verifica que no se creen instancias de las interfaces. Si 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 algún otro objeto. Esta anotación solo debe aparecer en literales de objetos.
Observa 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 prestan las propiedades.
Por ejemplo, En la documentación del kit de herramientas de JSDoc, 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 las licencias legales o el texto de derechos de autor) sobrevivan a la compilación sin cambios. Se conservan los saltos de línea. 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 las llamadas a la función si no se usa el valor de devolución. 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 intencionalmente un método o una propiedad de la superclase. Si no se incluyen otras anotaciones, el método o la propiedad heredan 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 privados para el paquete. Solo el código del 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étodos, funciones y constructores para especificar los tipos de argumentos de funciones. Las etiquetas
La etiqueta
Como alternativa, puedes anotar los tipos de los parámetros de forma intercalada (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; } /** * @param {{name: string, age: number}} person */ function logPerson({name, age}) { console.log(`${name} is ${age} years old`); } |
@private
|
Marca a 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 como Por ejemplo: /** * Handlers that are listening to this logger. * @private {Array<Function>} */ this.handlers_ = []; |
@protected
|
Indica que un miembro o una propiedad están protegidos.
Se puede acceder a 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 devolución de las definiciones de métodos y funciones.
La etiqueta
Como alternativa, puedes anotar el tipo de datos que se muestra de forma intercalada (consulta la función
Si una función que no está en externs no tiene un valor de devolución, 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 del objeto al que hace referencia la palabra clave
Para evitar 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. Actualmente, el verificador de tipos no usa esta información. Solo se usa para determinar si una función declarada en un archivo de externs tiene efectos secundarios. Por ejemplo: /** * @throws {DOMException} */ DOMApplicationCache.prototype.swapCache = function() { ... }; |
@type
|
Identifica el tipo de una variable, propiedad o expresión. La etiqueta Cuando declaras un parámetro de función o variable, puedes escribir la anotación de tipo intercalada omitiendo 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, los typedefs solo se pueden definir en el nivel superior, no dentro de las funciones. Corregimos esta limitación en la nueva inferencia de tipos. 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 de 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 tipos
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 que se describen 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 verificar el tipo de tu programa.
Ten en cuenta que el compilador de Closure no garantiza que podrá determinar el tipo de cada expresión de tu programa. Hace su mejor esfuerzo analizando cómo se usan las variables y las anotaciones de tipo adjuntas a sus declaraciones. Luego, usa varios algoritmos de inferencia de tipos para determinar el tipo de la mayor cantidad posible de expresiones. Algunos de estos algoritmos son sencillos ("si x es un número y vemos y = x;
, entonces y es un número"). Algunas son más indirectas ("si el primer parámetro de f se documenta 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. |
Escribe la aplicación |
{Array<string>} Un array de cadenas.
|
Parametriza un tipo con un conjunto de argumentos de tipo. Es similar a los genéricos de Java. |
Unión de tipos |
{(number|boolean)} 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 el tipo B. |
Tipo de registro |
{{myNum: number, myObject}}
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. Los corchetes forman parte de la sintaxis de tipos. 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 admiten valores nulos de forma predeterminada, independientemente de si se declaran con el operador Nullable. Un tipo de objeto se define como cualquier elemento, excepto una función, una cadena, un número o un valor booleano. Para hacer que un tipo de objeto no sea anulable, usa el operador Non-nullable. |
Tipo no anulable |
{!Object} 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 cadena) no son anulables de forma predeterminada, independientemente de si se declaran con el operador Non-nullable. Para hacer que un valor o un tipo de función sean anulables, usa el operador Nullable. |
Tipo de función |
{function(string, boolean)} Una función que toma dos parámetros (una cadena y un valor booleano) y tiene un valor de retorno desconocido. |
Especifica una función y los tipos de los parámetros de la función. |
Tipo de datos que devuelve la función |
{function(): number} Una función que no toma parámetros y devuelve un número. |
Especifica el tipo de valor que devuelve una función. |
Tipo de función this |
{function(this:goog.ui.Menu, string)} Una función que toma un parámetro (una cadena) y se ejecuta en el contexto de un goog.ui.Menu. |
Especifica el tipo del valor de this dentro de la función. |
Tipo de función new |
{function(new:goog.ui.Menu, string)} Una función que toma un parámetro (una cadena) 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 cadena) 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 para los parámetros variables. |
Parámetros de variables (en anotaciones de @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 Es un parámetro opcional de tipo number .
|
Indica que el argumento descrito por una anotación
Si una llamada a un 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 cadena opcional y anulable y un número opcional como argumentos. |
Indica que un argumento en un tipo de función es opcional. Un argumento opcional se puede omitir en la llamada a la función. Un argumento opcional no puede preceder a un argumento no opcional en la lista de argumentos. |
El tipo ALL | {*} |
Indica que la variable puede adoptar cualquier tipo. |
El tipo UNKNOWN | {?} |
Indica que la variable puede adoptar cualquier tipo y que el compilador no debe verificar el tipo de ninguno de sus usos. |
Conversión de tipos
Para convertir un valor a un tipo específico, usa esta sintaxis:
/** @type {!MyType} */ (valueExpression)
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 tipos en tiempo de compilación.
Puedes usar los genéricos para implementar colecciones generalizadas que contengan referencias a objetos de un tipo en particular y algoritmos generalizados que operen sobre objetos de un tipo en particular.
Cómo declarar un tipo genérico
Un tipo puede volverse genérico si se agrega una anotación @template
al constructor del tipo (para clases) o a la declaración de la interfaz (para 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
devolverá un objeto de tipo T
, y el método set
solo aceptará objetos de tipo T
.
Cómo crear una instancia de un tipo genérico
Si se reutiliza el ejemplo anterior, se puede crear una instancia basada en plantillas de Foo
de varias maneras:
/** @type {!Foo<string>} */ var foo = new Foo(); var foo = /** @type {!Foo<string>} */ (new Foo());
Ambas instrucciones del constructor anteriores crean una instancia de Foo
cuyo tipo de plantilla T
es string
. El compilador aplicará que las llamadas a los métodos de foo
y los accesos a las propiedades de foo
respeten 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 pueden tener un tipo implícito por 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 basadas en plantillas usarán el orden para asociar los tipos de plantilla con los valores. Por ejemplo:
/** @type {MyMap<string, number>} */ var map; // Key = string, Val = number.
Invariancia de los tipos genéricos
El compilador de Closure aplica la escritura de tipos genéricos invariantes. 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 plantilla pueden ser fijos o propagarse al tipo que hereda. 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 toma 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() { ... };
Cuando se extiende A<U>
, las instancias basadas en plantillas de C
tendrán un método method
que toma 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 se pueden hacer genéricos agregando 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