Type Vérification des fichiers JavaScript

Références

L'actualité

Librairie

L'information

Introduction

TypeScript 2.3 et les versions ultérieures prennent en charge la vérification du type et le signalement des erreurs dans les fichiers .js avec --checkJs.

Vous pouvez ignorer la vérification de certains fichiers en y ajoutant un commentaire // @ts-nocheck. Inversement, vous pouvez choisir de vérifier seulement quelques fichiers .js en leur ajoutant un commentaire // @ts-check sans les définir --checkJs. Vous pouvez également ignorer les erreurs sur des lignes spécifiques en les ajoutant // @ts-ignore à la ligne précédente. Notez que si vous avez une vérification tsconfig.json, JS respectera les indicateurs stricts tels que noImplicitAny, strictNullChecks etc... Cependant, en raison de la souplesse relative de la vérification JS, il peut être surprenant de combiner des indicateurs stricts.

Voici quelques différences notables sur le fonctionnement de la vérification dans les fichiers .js par rapport aux fichiers .ts :

Les types JSDoc sont utilisés pour les informations de type

Dans un fichier .js, les types peuvent souvent être déduits comme dans les fichiers .ts. De même, lorsque les types ne peuvent pas être déduits, ils peuvent être spécifiés à l'aide de JSDoc de la même manière que les annotations de type sont utilisées dans un fichier .ts. Tout comme Typescript, --noImplicitAny vous obtiendrez des erreurs aux endroits où le compilateur ne pourrait pas déduire un type. (à l'exception des littéraux d'objet ouverts; voir les détails ci-dessous.)

Les annotations JSDoc ornant une déclaration seront utilisées pour définir le type de cette déclaration.

Par exemple :

Vous pouvez trouver la liste complète des modèles JSDoc pris en charge dans le support JSDoc de la documentation JavaScript.

Les propriétés sont déduites des affectations dans les corps de classe

ES2015 ne dispose pas d'un moyen de déclarer des propriétés sur des classes. Les propriétés sont assignées dynamiquement, tout comme les littéraux d'objet.

Dans un fichier .js, le compilateur déduit les propriétés des attributions de propriétés à l'intérieur du corps de la classe. Le type de propriétés est le type indiqué dans le constructeur, sauf si ce n'est pas défini ici ou si le type dans le constructeur est indéfini ou null. Dans ce cas, le type est l'union des types de toutes les valeurs de droite dans ces affectations. Les propriétés définies dans le constructeur sont toujours supposées exister, alors que celles définies uniquement dans les méthodes, les getters ou les setters sont considérées comme facultatives.


Si les propriétés ne sont jamais définies dans le corps de la classe, elles sont considérées comme inconnues. Si votre classe a uniquement des propriétés en lecture, ajoutez puis annotez une déclaration dans le constructeur avec JSDoc pour spécifier le type. Vous n'avez même pas besoin de donner une valeur si elle sera initialisée plus tard :

Les fonctions du constructeur sont équivalentes aux classes

Avant ES2015, Javascript utilisait des fonctions de constructeur au lieu de classes. Le compilateur prend en charge ce modèle et comprend les fonctions de constructeur comme équivalentes aux classes ES2015. Les règles d'inférence de propriété décrites ci-dessus fonctionnent exactement de la même manière.

Les modules CommonJS sont pris en charge

Dans un fichier .js, Typescript comprend le format du module CommonJS. Les affectations à exportset module.exports sont reconnues en tant que déclarations d'exportation. De même, require les appels de fonction sont reconnus comme des importations de modules.

Par exemple :

Le support de module en Javascript est beaucoup plus tolérant sur le plan syntaxique que le support de module de Typescript. La plupart des combinaisons d'assignations et de déclarations sont prises en charge.

Les classes, les fonctions et les littéraux d'objet sont des espaces de noms

Les classes sont des espaces de noms dans des fichiers .js. Ceci peut être utilisé pour imbriquer des classes.

Par exemple :

Et, pour le code pré-ES2015, il peut être utilisé pour simuler des méthodes statiques :

Il peut également être utilisé pour créer des espaces de noms simples :

D'autres variantes sont également autorisées :

Les littéraux d'objet sont ouverts

Dans un fichier .ts, un littéral d'objet qui initialise une déclaration de variable donne son type à la déclaration. Aucun nouveau membre ne peut être ajouté qui n'a pas été spécifié dans le littéral d'origine. Cette règle est assouplie dans un fichier .js; les littéraux d'objet ont un type ouvert (une signature d'index) qui permet d'ajouter et de rechercher des propriétés qui n'étaient pas définies à l'origine.

Par exemple :

Les littéraux d'objet se comportent comme s'ils avaient une signature d'index [x:string] : any leur permettant d'être traités comme des cartes ouvertes au lieu d'objets fermés.

Comme d'autres comportements spéciaux de vérification JS, ce comportement peut être modifié en spécifiant un type JSDoc pour la variable.

Par exemple:

Les initialiseurs de tableaux nuls, non définis et vides sont de type any ou any[]

Toute variable, paramètre ou propriété initialisé avec null ou undefined aura le type any, même si les vérifications de null strictes sont activées. Toute variable, paramètre ou propriété initialisé avec [] aura le type [], même si les vérifications de null stricte sont activées. La seule exception concerne les propriétés ayant plusieurs initialiseurs, comme décrit ci-dessus.

Les paramètres de fonction sont optionnels par défaut

Dans la mesure où il n'existe aucun moyen de spécifier une option sur les paramètres dans le code Javascript antérieur à ES2015, tous les paramètres de fonction du fichier .js sont considérés comme facultatifs. Les appels avec moins d'arguments que le nombre déclaré de paramètres sont autorisés.

Il est important de noter que c'est une erreur d'appeler une fonction avec trop d'arguments.

Par exemple :

Les fonctions annotées JSDoc sont exclues de cette règle. Utilisez la syntaxe de paramètre facultatif JSDoc pour exprimer les options.

Par exemple :

Déclaration de paramètre Var-args déduite de l'utilisation de arguments

Une fonction dont le corps a une référence à la référence arguments est implicitement considérée comme ayant un paramètre var-arg (c'est-à-dire (...arg: any[]) => any). Utilisez la syntaxe JSDoc var-arg pour spécifier le type des arguments.

Les paramètres de type non spécifiés sont définis par défaut sur any

Comme il n'existe pas de syntaxe naturelle pour spécifier des paramètres de type générique en Javascript, un paramètre de type non spécifié par défaut est any.

En clause d'extension:

Par exemple, React.Component est défini pour avoir deux paramètres de type, Props et State. Dans un fichier .js, il n'existe aucun moyen légal de les spécifier dans la clause extend. Par défaut, les arguments de type seront any :

Utilisez JSDoc @augments pour spécifier explicitement les types.
Par exemple :

Dans les références JSDoc

Un argument de type non spécifié dans JSDoc utilise par défaut :

Dans les appels de fonction

Un appel à une fonction générique utilise les arguments pour déduire les paramètres de type. Parfois, ce processus ne permet pas d'inférer des types, principalement à cause du manque de sources d'inférence; dans ces cas, les paramètres de type seront par défaut à any.

Par exemple :


JSDoc pris en charge

La liste ci-dessous indique les constructions actuellement prises en charge lors de l'utilisation d'annotations JSDoc pour fournir des informations de type dans des fichiers JavaScript.

Notez que les balises qui ne sont pas explicitement listées ci-dessous (telles que @async) ne sont pas encore prises en charge.

  • @type
  • @param (ou @argou @argument)
  • @returns (ou @return)
  • @typedef
  • @callback
  • @template
  • @class (ou @constructor)
  • @this
  • @extends (ou @augments)
  • @enum

La signification est généralement la même, ou un sur-ensemble, de la signification de la balise donnée sur usejsdoc.org. Le code ci-dessous décrit les différences et donne un exemple d'utilisation de chaque balise.

@type

Vous pouvez utiliser la balise @type et référencer un nom de type (primitive, définie dans une déclaration TypeScript ou dans une balise JSDoc @typedef Vous pouvez utiliser n'importe quel type de typescript et la plupart des types JSDoc.

@type peut spécifier un type d'union, par exemple, quelque chose peut être une chaî ne ou un booléen.

Notez que les parenthèses sont facultatives pour les types d'union.

Vous pouvez spécifier des types de tableaux en utilisant diverses syntaxes :

Vous pouvez également spécifier des types littéraux d'objet. Par exemple, un objet avec les propriétés 'a' (chaî ne) et 'b' (nombre) utilise la syntaxe suivante :

Vous pouvez spécifier des objets de type carte et de type tableau à l'aide de signatures d'index de chaî ne et de nombre, à l'aide de la syntaxe JSDoc standard ou de la syntaxe Typescript.

Les deux types précédents sont équivalents aux types Typescript { [x: string]: number } et { [x: number]: any }. Le compilateur comprend les deux syntaxes.

Vous pouvez spécifier les types de fonction à l'aide de la syntaxe Typescript ou Closure:

Ou vous pouvez simplement utiliser le Functiontype non spécifié :

D'autres types de fermeture fonctionnent également :

Les moulages

Typescript emprunte la syntaxe de conversion de Closure. Cela vous permet de convertir des types en d'autres types en ajoutant une @typebalise avant toute expression entre parenthèses.

Types d'importation

Vous pouvez également importer des déclarations à partir d'autres fichiers à l'aide de types d'importation. Cette syntaxe est spécifique à Typescript et diffère de la norme JSDoc :

Les types d'importation peuvent également être utilisés dans les déclarations d'alias de type :

Les types d'importation peuvent être utilisés pour obtenir le type d'une valeur à partir d'un module si vous ne connaissez pas le type ou s'il a un type de grande taille qui est ennuyeux à taper:

@param et @returns

@param utilise la même syntaxe de type que @type, mais ajoute un nom de paramètre.
Le paramètre peut également être déclaré facultatif en entourant le nom de crochets :

De même, pour le type de retour d'une fonction :

@typedef, @callback et @param

@typedef peut être utilisé pour définir des types complexes. Une syntaxe similaire fonctionne avec @param.

Vous pouvez utiliser l'une object ou l'autre ou Object sur la première ligne.

@param permet une syntaxe similaire pour les spécifications de type ponctuelles. Notez que les noms de propriété imbriqués doivent être précédés du nom du paramètre :

@callback est similaire à @typedef, mais spécifie un type de fonction au lieu d'un type d'objet :

Bien entendu, chacun de ces types peut être déclaré à l'aide de la syntaxe Typescript sur une seule ligne @typedef :

@template

Vous pouvez déclarer des types génériques avec la balise @template :

Utilisez des virgules ou plusieurs balises pour déclarer plusieurs paramètres de type :

Vous pouvez également spécifier une contrainte de type avant le nom du paramètre de type. Seul le premier paramètre de type dans une liste est contraint :

@constructor

Le compilateur induit des fonctions de constructeur basées sur les affectations this-property, mais vous pouvez améliorer la vérification et les suggestions plus strictes si vous ajoutez une balise @constructor :

Avec @constructor, this est cochée dans la fonction constructeur C, vous obtiendrez ainsi des suggestions pour la méthode initialize et une erreur si vous lui transmettez un nombre. Vous obtiendrez également une erreur si vous appelez C au lieu de la construire.

Malheureusement, cela signifie que les fonctions de constructeur également appelables ne peuvent pas être utilisées @constructor.

@this

Le compilateur peut généralement déterminer le type de moment this où il doit travailler avec un certain contexte. Sinon, vous pouvez spécifier explicitement le type de this avec @this :

@extends

Lorsque les classes Javascript étendent une classe de base générique, il n'y a nulle part où spécifier le paramètre type. La balise @extends fournit une place pour ce paramètre de type :

Notez que @extends ne fonctionne qu'avec des classes. Actuellement, il n'y a aucun moyen pour une fonction constructeur d'étendre une classe.

@enum

La balise @enum vous permet de créer un littéral d'objet dont les membres sont tous d'un type spécifié. Contrairement à la plupart des littéraux d'objet en Javascript, il ne permet pas aux autres membres.

Notez que @enum est assez différent et beaucoup plus simple que celui de Typescript enum. Cependant, contrairement aux énumérations de Typescript, @enum peut avoir n'importe quel type :

Plus d'exemples :

Modèles qui ne sont pas connus pour être pris en charge

Faire référence à des objets dans l'espace de valeur en tant que types ne fonctionne que si l'objet crée également un type, comme une fonction constructeur.

Postfix est égal à un type de propriété dans un type d'objet littéral ne spécifie pas une propriété facultative :

Les types nullables n'ont de signification que si strictNullChecks est activé :

Les types non nullables n'ont aucune signification et sont traités comme leur type d'origine :

Contrairement au système de types de JSDoc, Typescript vous permet uniquement de marquer les types comme contenant null ou non. Il n'y a pas de non-possibilité explicite si strictNullChecks est activé, alors number n'est pas nullable. Si elle est désactivée, alors number est nullable.