Annoter le code JavaScript pour le compilateur de fermeture

Remarque: Cette page est obsolète. La liste complète est disponible à l'adresse https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler.

Présentation

Closure Compiler peut utiliser les informations de type de données sur les variables JavaScript pour améliorer l'optimisation et afficher des avertissements. Toutefois, JavaScript ne permet pas de déclarer des types.

Comme JavaScript n'a pas de syntaxe pour déclarer le type d'une variable, vous devez utiliser des commentaires dans le code pour spécifier le type de données.

Le langage de type de Closure Compiler est dérivé des annotations utilisées par l'outil de génération de documents JSDoc, bien qu'il ait depuis divergé. Il inclut désormais plusieurs annotations non compatibles avec JSDoc, et inversement. Ce document décrit l'ensemble d'annotations et d'expressions de type acceptées par le Closure Compiler.

  1. Balises JSDoc
  2. Expressions de type
  3. Types génériques

Balises JSDoc

Closure Compiler recherche des informations de type dans les tags JSDoc. Utilisez les balises JSDoc décrites dans le tableau de référence ci-dessous pour aider le compilateur à optimiser votre code et à vérifier qu'il ne comporte pas d'erreurs de type et d'autres erreurs.

Ce tableau n'inclut que les balises qui affectent le comportement de Closure Compiler. Pour en savoir plus sur les autres balises JSDoc, consultez la documentation du kit JSDoc.

Balise Description
@abstract

Marque une méthode comme abstraite. À l'instar de la définition d'une méthode sur goog.abstractMethod, le compilateur peut éliminer des méthodes annotées avec @abstract pour réduire la taille du code.

Le compilateur génère un avertissement si une méthode marquée avec @abstract a une implémentation non vide.

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

Marque une variable comme étant en lecture seule. Le compilateur peut intégrer des variables @const, ce qui optimise le code JavaScript.

La déclaration du type est facultative.

Le compilateur génère un avertissement si une valeur est attribuée à une variable plusieurs fois avec @const. Si la variable est un objet, notez que le compilateur n'interdit pas de modifier les propriétés de l'objet.

Par exemple :
/** @const */ var MY_BEER = 'stout';

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

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

Marque une fonction en tant que constructeur. Le compilateur nécessite une annotation @constructor pour toute fonction utilisée avec le mot clé new.

Exemple :

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define Indique une constante pouvant être remplacée par le compilateur au moment de la compilation. Dans l'exemple de gauche, vous pouvez transmettre l'indicateur --define='ENABLE_DEBUG=false' au compilateur pour remplacer la valeur de ENABLE_DEBUG par false. Le type d'une constante définie peut être un nombre, une chaîne ou une valeur booléenne. Les définitions ne sont autorisées que dans le champ d'application global.

Exemple :

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

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

Marque une fonction, une méthode ou une propriété de sorte que son utilisation génère un avertissement du compilateur indiquant qu'elle ne doit plus être utilisée.

Exemple :

/**
 * 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 permet de créer des objets avec un nombre variable de propriétés. Lorsqu'un constructeur (Foo dans l'exemple) est annoté avec @dict, vous ne pouvez utiliser que la notation entre crochets pour accéder aux propriétés des objets Foo. L'annotation peut également être utilisée directement sur des littéraux d'objet.

Exemple :

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

Spécifie le type d'énumération. Une énumération est un objet dont les propriétés constituent un ensemble de constantes associées. Le tag @enum doit être suivi d'une expression de type.

Le libellé de type d'une énumération s'applique à chaque propriété de l'énumération. Par exemple, si une énumération est de type number, chacune de ses propriétés énumérées doit être un nombre. Si le type d'une énumération est omis, la valeur number est déduite par défaut.

Exemple :

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

Avec ce code

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

Lorsque le compilateur est exécuté avec l'option --generate_exports, il génère le code suivant:

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

qui exportera les symboles vers du code non compilé. Vous pouvez écrire /** @export {SomeType} */ en tant que raccourci pour

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

Le code qui utilise l'annotation @export doit soit

  1. inclure closure/base.js ou
  2. définir à la fois goog.exportSymbol et goog.exportProperty avec la même signature de méthode dans leur propre codebase ;
@extends

Marque une classe ou une interface comme héritant d'une autre classe. Une classe marquée avec @extends doit également être marquée avec @constructor ou @interface.

Remarque : @extends n'entraîne pas l'héritage d'une classe à partir d'une autre classe. L'annotation indique simplement au compilateur qu'il peut traiter une classe comme une sous-classe d'une autre pendant la vérification du type.

Pour obtenir un exemple de mise en œuvre de l'héritage, consultez la page sur la fonction Closure Librarygoog.inherits().

Exemple :

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

Indique que cette classe ne peut pas être étendue. Pour les méthodes, indique qu'aucune sous-classe n'est autorisée à remplacer cette méthode.

Exemple :

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

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

Utilisé avec @constructor pour indiquer qu'une classe implémente une interface.

Le compilateur génère un avertissement si vous taguez un constructeur à l'aide de @implements, puis ne parvenez pas à implémenter toutes les méthodes et propriétés définies par l'interface.

Exemple :


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

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

Cette annotation ne peut apparaître que dans des déclarations de propriété externes. La propriété possède un type déclaré, mais vous pouvez lui attribuer n'importe quel type sans avertissement. Lorsque vous accédez à la propriété, vous obtenez une valeur du type déclaré. Par exemple, element.innerHTML peut être attribué à n'importe quel type, mais renvoie toujours une chaîne.

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

Indique qu'une méthode ou une propriété d'une sous-classe masque intentionnellement une méthode ou une propriété de la super-classe et qu'elle contient exactement la même documentation. Notez que le tag @inheritDoc implique le tag @override.

Exemple :

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

Marque une fonction en tant qu'interface. Une interface spécifie les membres requis d'un type. Toute classe qui implémente une interface doit implémenter toutes les méthodes et propriétés définies sur le prototype de l'interface. Consultez @implements.

Le compilateur vérifie que les interfaces ne sont pas instanciées. Si le mot clé new est utilisé avec une fonction d'interface, le compilateur génère un avertissement.

Exemple :

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

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

Indique que les clés d'un littéral d'objet doivent être traitées comme les propriétés d'un autre objet. Cette annotation ne doit apparaître que sur les littéraux d'objet.

Notez que le nom entre accolades ne correspond pas à un nom de type comme dans les autres annotations. Il s'agit d'un nom d'objet. Elle nomme l'objet auquel les propriétés sont prêtées. Par exemple, @type {Foo} signifie "une instance de Foo", tandis que @lends {Foo} signifie "le constructeur Foo".

La documentation du kit JSDoc contient plus d'informations sur cette annotation.

Exemple :

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

Indique au compilateur d'insérer le commentaire associé avant le code compilé pour le fichier marqué. Cette annotation permet aux avis importants (tels que les licences légales ou le texte de droits d'auteur) de rester inchangés. Les sauts de ligne sont conservés.

Exemple :

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

Indique une propriété qui ne doit pas être réduite par le compilateur en une variable. La principale utilisation de @nocollapse consiste à autoriser l'exportation de propriétés modifiables. Notez que le compilateur peut renommer les propriétés non réduites. Si vous annotez une propriété qui est un objet avec @nocollapse, toutes ses propriétés resteront également non réduites.

Exemple :

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

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

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

Indique qu'un appel à la fonction externe déclarée n'a aucun effet secondaire. Cette annotation permet au compilateur de supprimer les appels à la fonction si la valeur de retour n'est pas utilisée. L'annotation n'est autorisée que dans extern files.

Exemple :

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

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

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

Indique qu'une méthode ou une propriété d'une sous-classe masque intentionnellement une méthode ou une propriété de la super-classe. Si aucune autre annotation n'est incluse, la méthode ou la propriété hérite automatiquement des annotations de sa super-classe.

Exemple :

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

Marque un membre ou une propriété comme privé. Seul le code du même répertoire peut accéder aux noms marqués @package. En particulier, le code des répertoires parent et enfant ne peut pas accéder aux noms marqués @package.

Les constructeurs publics peuvent disposer de propriétés @package pour restreindre les méthodes que les appelants externes à l'annuaire peuvent utiliser. En revanche, les constructeurs @package peuvent disposer de propriétés publiques pour empêcher les appelants en dehors du répertoire d'instancier directement un type.

Exemple :

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

Utilisé avec les définitions de méthode, de fonction et de constructeur pour spécifier les types d'arguments de la fonction. Les tags @param doivent être dans le même ordre que les paramètres de la définition de la fonction.

Le tag @param doit être suivi d'une expression de type.

Vous pouvez également annoter les types de paramètres intégrés (voir la fonction foo dans l'exemple).

Exemple :


/**
 * 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;
}
Pour les paramètres qui représentent un modèle de déstructuration, vous pouvez utiliser n'importe quel nom correspondant à un identifiant JS valide après l'annotation de type.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Marque un membre comme privé. Seul le code du même fichier peut accéder aux fonctions et variables globales marquées @private. Les constructeurs marqués @private ne peuvent être instanciés que par du code contenu dans le même fichier, ainsi que par leurs membres statiques et ceux de l'instance.

Les propriétés statiques publiques des constructeurs marqués comme @private sont également accessibles partout, et l'opérateur instanceof peut toujours accéder aux membres @private.

Exemple :

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

@protected

Indique qu'un membre ou une propriété est protégé.

Une propriété marquée comme @protected est accessible à:

  • tout le code du même fichier
  • les méthodes statiques et les méthodes d'instance de toute sous-classe de la classe sur laquelle la propriété est définie.

Exemple :

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

Marque une fonction comme une interface structurelle. Une interface structurelle est semblable à une @interface nominale, mais elle permet des mises en œuvre implicites. Cela signifie que toute classe incluant les méthodes et propriétés définies dans le prototype de l'interface structurelle met en œuvre l'interface structurelle, qu'elle utilise ou non le tag @implements. Les types d'enregistrements et les littéraux d'objet mettent également en œuvre implicitement une interface structurelle s'ils contiennent les propriétés requises.

Exemple :

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

Spécifie les types de renvoi des définitions de méthode et de fonction. Le tag @return doit être suivi d'une expression de type.

Vous pouvez également annoter le type de retour intégré (voir la fonction foo dans l'exemple).

Si une fonction qui n'est pas dans des externs n'a pas de valeur renvoyée, vous pouvez omettre le tag @return. Le compilateur supposera alors que la fonction renvoie undefined.

Exemple :

/**
 * 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 permet de créer des objets avec un nombre fixe de propriétés. Lorsqu'un constructeur (Foo dans l'exemple) est annoté avec @struct, vous ne pouvez utiliser que la notation par points pour accéder aux propriétés des objets Foo, et non à la notation entre crochets. Vous ne pouvez pas non plus ajouter une propriété à une instance Foo après sa construction. L'annotation peut également être utilisée directement sur des littéraux d'objet.

Exemple :

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

Consultez Types génériques.

Exemple :

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

Spécifie le type d'objet auquel le mot clé this fait référence dans une fonction. Le tag @this doit être suivi d'une expression de type.

Pour éviter les avertissements du compilateur, vous devez utiliser une annotation @this chaque fois que this apparaît dans une fonction qui n'est ni une méthode de prototype, ni une fonction marquée comme @constructor.

Exemple :

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

Utilisée pour documenter les exceptions générées par une fonction. L'outil de vérification des types n'utilise pas ces informations pour le moment. Elle ne sert qu'à déterminer si une fonction déclarée dans un fichier externe a des effets secondaires.

Exemple :

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

Identifie le type d'une variable, d'une propriété ou d'une expression. Le tag @type doit être suivi d'une expression de type.

Lorsque vous déclarez un paramètre de variable ou de fonction, vous pouvez écrire l'annotation de type de façon intégrée en omettant {} et @type, comme dans le deuxième exemple. Ce raccourci ne peut être effectué que lorsqu'une variable ou un paramètre de fonction est déclaré. Si vous souhaitez ajuster le type plus tard, vous aurez besoin d'une cast type.

Exemple :

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

Déclare un alias pour un type plus complexe. Actuellement, les types de définition ne peuvent être définis qu'au niveau supérieur, et non à l'intérieur des fonctions. Nous avons corrigé cette limite dans l'inférence de nouveau type.

Exemple :

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

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

Indique qu'une classe n'est ni de type @struct, ni de type @dict. Il s'agit du format par défaut. Il n'est donc généralement pas nécessaire de l'écrire explicitement, sauf si vous utilisez goog.defineClass ou le mot clé class, qui produisent tous deux des classes qui sont des @struct par défaut.

Exemple :

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

Expressions de type

Vous pouvez spécifier le type de données de n'importe quelle variable, propriété, expression ou paramètre de fonction avec une expression de type. Une expression de type est constituée d'accolades ("{ }") contenant une combinaison des opérateurs de type décrits ci-dessous.

Utilisez une expression de type avec la balise @param pour déclarer le type d'un paramètre de fonction. Utilisez une expression de type avec la balise @type pour déclarer le type d'une variable, d'une propriété ou d'une expression.

Plus vous spécifiez de types dans votre code, plus le compilateur peut optimiser les optimisations et plus il peut détecter d'erreurs.

Le compilateur utilise ces annotations pour vérifier le type de votre programme. Notez que Closure Compiler ne garantit pas qu'il sera en mesure de déterminer le type de chaque expression dans votre programme. Nous nous efforcerons de vérifier la façon dont les variables sont utilisées et les annotations de types associées à leurs déclarations. Ensuite, elle utilise un certain nombre d'algorithmes d'inférence de type pour déterminer le type d'un maximum d'expressions. Certains de ces algorithmes sont simples ("si x est un nombre et que nous voyons y = x;, alors y est un nombre"). Certains sont plus indirects (si le premier paramètre de f est documenté en tant que rappel devant accepter un nombre et que nous observons f(function(x) { /** ... */ });, alors x doit être un nombre).

Nom de l'opérateur Exemples de syntaxe Description
Nom du type {boolean}
{Window}
{goog.ui.Menu}
Spécifie le nom d'un type.
Type : Application {Array<string>}
Tableau de chaînes.

{Object<string, number>}
Objet dans lequel les clés sont des chaînes et les valeurs sont des nombres.

Paramètre un type avec un ensemble d'arguments de type. Semblable aux génériques Java.
Type Union {(number|boolean)}
Nombre ou valeur booléenne.

Notez les parenthèses, qui sont obligatoires.
Indique qu'une valeur peut être de type A OU B.
Type d'enregistrement {{myNum: number, myObject}}
Type anonyme avec une propriété nommée myNum dont la valeur est de type number et une propriété nommée myObject dont la valeur est de n'importe quel type.

Indique que la valeur comprend les membres spécifiés avec les valeurs des types spécifiés.

Les accolades font partie de la syntaxe des types. Par exemple, pour indiquer une propriété Array d'objets ayant une propriété length, vous pouvez écrire
Array<{length}>. Dans l'exemple de gauche, les accolades externes indiquent qu'il s'agit d'une expression de type et les accolades intérieures indiquent qu'il s'agit d'un type d'enregistrement.

Type null {?number}
Un nombre ou null.

Indique qu'une valeur est de type A ou null.

Tous les types d'objets peuvent être vides par défaut, qu'ils soient déclarés à l'aide de l'opérateur Nullable ou non. Un type d'objet est défini comme n'importe quel élément à l'exception d'une fonction, d'une chaîne, d'un nombre ou d'une valeur booléenne. Pour rendre un type d'objet ne pouvant être vide, utilisez l'opérateur Non-nullable.

Type ne pouvant être vide {!Object}
Un objet, mais jamais la valeur null.

Indique qu'une valeur est de type A et non nulle.

Les fonctions et tous les types de valeurs (booléen, nombre et chaîne) ne peuvent pas être nuls par défaut, qu'ils soient déclarés ou non avec l'opérateur "Non nul". Pour rendre une valeur ou un type de fonction pouvant être vide, utilisez l'opérateur Nullable.

Type de fonction {function(string, boolean)}
Fonction qui accepte deux paramètres (une chaîne et une valeur booléenne) et dont la valeur affichée est inconnue.
Spécifie une fonction et les types de ses paramètres.
Type de renvoi de la fonction {function(): number}
Une fonction qui ne prend aucun paramètre et renvoie un nombre.
Spécifie le type de valeur renvoyée par une fonction.
Type de fonction this {function(this:goog.ui.Menu, string)}
Fonction qui prend un paramètre (une chaîne) et s'exécute dans le contexte d'un goog.ui.Menu.
Spécifie le type de valeur de this dans la fonction.
Type de fonction new {function(new:goog.ui.Menu, string)}
Fonction qui utilise un paramètre (une chaîne) et crée une instance de goog.ui.Menu lorsqu'elle est appelée avec le mot clé "new".
Spécifie le type construit d'un constructeur.
Paramètres de variable {function(string, ...number): number}
Fonction qui accepte un paramètre (une chaîne), puis un nombre variable de paramètres qui doivent être des nombres.
Indique qu'un type de fonction accepte un nombre variable de paramètres et spécifie un type pour les paramètres des variables.
Paramètres variables (dans les annotations @param) @param {...number} var_args
Nombre variable de paramètres pour une fonction annotée.
Indique que la fonction annotée accepte un nombre variable de paramètres et spécifie un type pour les paramètres de la variable.
Paramètre facultatif d'une annotation @param @param {number=} opt_argument
Paramètre facultatif de type number.

Indique que l'argument décrit par une annotation @param est facultatif. Un appel de fonction peut omettre un argument facultatif. Un paramètre facultatif ne peut pas précéder un paramètre non facultatif de la liste des paramètres.

Si un appel de méthode omet un paramètre facultatif, cet argument aura la valeur undefined. Par conséquent, si la méthode stocke la valeur du paramètre dans une propriété de classe, la déclaration du type de cette propriété doit inclure une valeur possible de undefined, comme dans l'exemple suivant:

/**
 * 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;
}
Argument facultatif dans un type de fonction {function(?string=, number=)}
Fonction qui utilise une chaîne facultative nul et un nombre facultatif comme arguments.
Indique qu'un argument dans un type de fonction est facultatif. Un argument facultatif peut être omis de l'appel de fonction. Un argument facultatif ne peut pas précéder un argument non facultatif de la liste des arguments.
Le type ALL [TOUTES] {*} Indique que la variable peut accepter n'importe quel type.
Type UNKNOWN {?} Indique que la variable peut accepter n'importe quel type, et que le compilateur ne doit en vérifier aucune utilisation.

Caster un type

Pour caster une valeur vers un type spécifique, utilisez cette syntaxe

/** @type {!MyType} */ (valueExpression)
Les parenthèses entourant l'expression sont toujours obligatoires.

Types génériques

Tout comme Java, Closure Compiler est compatible avec les types, fonctions et méthodes génériques. Les caractères génériques opèrent sur des objets de différents types tout en préservant la sécurité du type de compilation.

Vous pouvez utiliser des génériques pour implémenter des collections généralisées qui contiennent des références à des objets d'un type particulier, et des algorithmes généralisés qui agissent sur des objets d'un type particulier.

Déclarer un type générique

Un type peut être générique en ajoutant une annotation @template au constructeur du type (pour les classes) ou à la déclaration d'interface (pour les interfaces). Exemple :

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

L'annotation @template T indique que Foo est un type générique avec un type de modèle, T. Le type de modèle T peut être utilisé comme type de champ d'application dans la définition de Foo. Exemple :

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

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

La méthode get renvoie un objet de type T, et la méthode set n'accepte que les objets de type T.

Instanciation d'un type générique

En reprenant l'exemple ci-dessus, une instance modélisée de Foo peut être créée de plusieurs manières:

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

Les deux instructions de constructeur ci-dessus créent une instance Foo dont le type de modèle T est string. Le compilateur appliquera les appels aux méthodes de foo et l'accès aux propriétés de foo, tout en respectant le type de modèle. Exemple :

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

Les instances peuvent également être tapées implicitement par leurs arguments de constructeur. Prenons l'exemple d'un autre type générique, Bar:

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

Le type de l'argument du constructeur Bar est déduit en tant que string. Par conséquent, l'instance créée bar est déduite en tant que Bar<string>.

Plusieurs types de modèles

Un modèle générique peut avoir un nombre illimité de types de modèles. La classe de carte suivante comporte deux types de modèles:

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

Tous les types de modèles d'un type générique doivent être spécifiés dans la même annotation @template, sous la forme d'une liste d'éléments séparés par une virgule. L'ordre des noms de types de modèles est important, car les annotations de type de modèle utilisent l'ordre pour associer les types de modèle aux valeurs. Exemple :

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

Invariance des types génériques

Closure Compiler applique une saisie générique invariante. Cela signifie que si un contexte attend un type Foo<X>, vous ne pouvez pas transmettre un type Foo<Y> lorsque X et Y sont des types différents, même si l'un est un sous-type de l'autre. Exemple :

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

Héritage des types génériques

Les types génériques peuvent être hérités, et leurs types de modèle peuvent être corrigés ou propagés vers le type hérité. Voici un exemple de type héritant qui corrige le type de modèle de son supertype:

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

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

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

En étendant A<string>, B possède une méthode method qui utilise un paramètre de type string.

Voici un exemple de type héroïque propageant le type de modèle de son supertype:

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

Si vous étendez A<U>, les instances modélisées de C auront une méthode method qui accepte un paramètre du type de modèle U.

Les interfaces peuvent être implémentées et étendues de la même manière, mais un même type ne peut pas implémenter la même interface plusieurs fois avec des types de modèles différents. Exemple :

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

Fonctions et méthodes génériques

Comme pour les types génériques, les fonctions et les méthodes peuvent être génériques en ajoutant une annotation @template à leur définition. Exemple :

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