Menu

any vs unknown en TypeScript : différences et cas d'usage

any et unknown acceptent toutes les valeurs. any désactive la vérification des types pour cette valeur, alors que unknown vous oblige à la vérifier avant de l'utiliser. Découvrez les différences, comment affiner unknown, noImplicitAny, et par où any se glisse dans du code typé.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

any et unknown acceptent toutes les valeurs. La différence tient à ce que vous pouvez faire ensuite avec la valeur : any vous laisse tout faire et ne vérifie rien, alors que unknown ne vous laisse presque rien faire tant que vous n'avez pas prouvé ce qu'est la valeur.

Sans la ligne @ts-expect-error, u.toUpperCase() provoque l'erreur de compilation TS18046. La vérification typeof affine u en string, et dans ce bloc toutes les méthodes de chaîne sont disponibles.

any ou unknown en un coup d'œil

anyunknown
Accepte n'importe quelle valeurouioui
L'assigner à un string, un number...oui, sans vérificationnon (TS2322)
Lire une propriété, appeler une méthodeoui, sans vérificationnon (TS18046)
L'appeler comme une fonctionouinon
Calculs et comparaisons (x * 2, x + 1, x < 5)ouinon (TS18046)
Demande une vérification avant usagenonoui (typeof, instanceof, in, un type guard)
Effet sur la vérification des typesdésactivée pour cette valeur et tout ce qu'elle toucheconservée

En termes de théorie des types, unknown est le type supérieur (top type) : tout type lui est assignable, et il n'est assignable qu'à unknown et à any. any est une échappatoire assignable dans les deux sens, à tout sauf never.

any désactive la vérification des types

Une valeur typée any bénéficie d'une confiance aveugle. Le compilateur accepte les fautes de frappe, les mauvais types et les propriétés manquantes, et les erreurs apparaissent à l'exécution à la place.

La sortie montre le problème : une variable annotée number contient une chaîne, et la dernière ligne lève Cannot read properties of undefined (reading 'city'). any se propage aussi. user.name est any, donc toute valeur calculée à partir de lui est any, et une seule valeur non typée peut désactiver la vérification loin de l'endroit où elle est entrée.

unknown vous oblige à vérifier d'abord

Avec unknown, le compilateur refuse toute opération tant que le code n'a pas affiné la valeur. L'affinage utilise des vérifications JavaScript ordinaires, et dans chaque branche la valeur a le type vérifié.

La vérification value === null doit précéder celle de l'objet, car typeof null vaut "object". Après "id" in value, TypeScript sait que l'objet possède une propriété id, typée unknown, puisque rien n'indique ce qu'elle contient. String() la convertit explicitement en texte ; pour l'utiliser comme un nombre, il faudrait d'abord la vérifier avec typeof.

Vous pouvez aussi sauter la vérification avec une assertion, value as string, et le compilateur l'accepte. C'est une promesse sans aucune vérification à l'exécution derrière elle : préférez une vraie vérification ; voir assertions de type.

Valider du JSON avec unknown

JSON.parse est déclaré comme renvoyant any, son résultat désactive donc la vérification en silence. Annotez le résultat en unknown et écrivez un type guard qui vérifie la forme avant que le reste du code ne lui fasse confiance.

La première entrée affiche dark at 14px, la seconde est refusée car fontSize manque. Avec any, la seconde entrée aurait circulé comme un Settings avec un fontSize indéfini. Pour les gros schémas, une bibliothèque de validation fait le même travail et dérive le type pour vous.

noImplicitAny

any ne vient pas seulement de ceux qui l'écrivent. Un paramètre sans annotation et sans contexte d'inférence serait any lui aussi. L'option noImplicitAny, activée par strict, signale cela comme une erreur :

index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type.

La correction est une annotation, function double(x: number). Écrire explicitement x: any compile aussi, et c'est justement le but : any reste visible dans le code, on peut le rechercher et le relire.

Par où any se glisse encore

Même avec strict, ces cas produisent any sans que le mot n'apparaisse dans votre code :

SourceCe que vous obtenezQue faire
JSON.parse(text)anyannoter en unknown, puis valider
response.json() avec les types du navigateur (DOM)Promise<any>comme pour JSON.parse (les types du fetch de Node renvoient déjà Promise<unknown>)
Un paquet sans définitions de typesany pour ses imports (avec une erreur tant que vous n'ajoutez pas de déclaration)installer @types/... ou écrire un .d.ts
value as anyanyutiliser un type guard ou une assertion précise
catch (e) avec useUnknownInCatchVariables désactivéanystrict le rend unknown ; gardez-le ainsi

La variable de catch est unknown avec strict, car on peut lever n'importe quoi, pas seulement des objets Error. Affinez-la avec e instanceof Error avant de lire e.message.

Quand any est acceptable

any n'est pas interdit, mais chaque occurrence est un endroit que le compilateur ne protège plus. Usages raisonnables :

  • La migration d'une base de code JavaScript, où any marque ce qui n'est pas encore typé.
  • Du code que le système de types exprime mal, gardé petit et derrière une signature de fonction typée.
  • Du code de test qui passe volontairement de mauvaises données.

Pour tout le reste, unknown couvre le même cas « je ne connais pas ce type » tout en gardant les vérifications. Beaucoup d'équipes l'imposent avec la règle de lint @typescript-eslint/no-explicit-any. Un type voisin, Record<string, unknown>, est le choix habituel pour « un objet aux valeurs inconnues ».

Questions fréquentes

Quelle est la différence entre any et unknown en TypeScript ?

Les deux acceptent n'importe quelle valeur. Avec any, vous pouvez tout faire avec la valeur (lire des propriétés, l'appeler, l'assigner à un number) et le compilateur ne vérifie rien. Avec unknown, vous ne pouvez presque rien faire tant que vous ne l'avez pas affinée par une vérification comme typeof x === "string". unknown garde la vérification des types active, c'est pourquoi c'est le choix le plus sûr.

Quand utiliser unknown plutôt que any ?

Chaque fois que le type d'une valeur n'est pas connu à la compilation : JSON analysé, données d'une réponse réseau, erreur capturée, entrée d'une fonction de validation. Typez-la unknown et affinez-la. Ne recourez à any que pour un travail de migration temporaire ou du code que le système de types ne sait pas décrire.

Que signifie « Object is of type 'unknown' » ?

Les erreurs TS18046 ('x' is of type 'unknown') et TS2571 (Object is of type 'unknown', utilisée quand la valeur n'est pas un simple nom, comme load().id) signifient que vous avez utilisé une valeur unknown comme si elle avait un type précis, par exemple en lisant une propriété ou en appelant une méthode. Vérifiez d'abord le type (typeof, instanceof, Array.isArray, in, ou une fonction type guard), et utilisez la valeur dans la branche affinée.

Pourquoi JSON.parse renvoie-t-il any ?

Sa déclaration dans la bibliothèque standard indique parse(text: string, ...): any, car le compilateur ne peut pas savoir ce que contient une chaîne. Le résultat désactive en silence la vérification de tout ce qu'il touche. Annotez-le plutôt : const data: unknown = JSON.parse(text), puis validez-le avant de l'utiliser.

Qu'est-ce que noImplicitAny ?

Une option du compilateur, incluse dans strict, qui signale une erreur quand une déclaration recevrait en silence le type any faute d'annotation et de quoi inférer : TS7006 pour un paramètre, TS7005 ou TS7034 pour une variable dont le type ne peut pas être déterminé. Elle empêche any d'apparaître sans que personne ne l'ait écrit. Un any explicite reste autorisé.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER