Les deux veulent dire « je ne connais pas le type ». Mais any et unknown sont
des opposés : l’un désactive les vérifications, l’autre les renforce. Bien
choisir entre les deux, c’est décider si tu gardes ou non le filet de sécurité de
TypeScript.
any : le trou dans le typage
Une valeur any accepte tout, et laisse tout faire. Le compilateur se tait —
y compris sur les erreurs :
let x: any = "hello";
x.toFixed(2); // aucune erreur à la compilation… plante à l'exécution
x.foo.bar.baz; // aucune erreur non plusany est contagieux : tout ce qui en dérive devient any à son tour. Une
seule valeur mal typée peut éteindre les garanties d’une moitié de ton fichier
sans que tu t’en aperçoives.
unknown : l’inconnu honnête
unknown accepte aussi n’importe quelle valeur en entrée. Mais à la sortie,
il ne te laisse rien faire tant que tu n’as pas prouvé le type :
let x: unknown = "hello";
x.toFixed(2); // ❌ Error: 'x' is of type 'unknown'
if (typeof x === "string") {
x.toUpperCase(); // ✅ ici, x est prouvé string
}Même sécurité d’entrée que any, mais le compilateur t’oblige à vérifier
avant d’utiliser. L’incertitude est explicite, pas balayée sous le tapis.
La règle pratique
Aux frontières de ton programme — un JSON.parse, une réponse d’API, un
catch (e) — tu reçois des données dont tu ne connais pas la forme. Type-les
unknown, pas any :
async function loadUser(): Promise<User> {
const data: unknown = await res.json();
return parseUser(data); // une fonction qui valide et renvoie un User
}Tu gardes le « je ne sais pas » honnête de unknown, et tu le transformes en
certitude au seul endroit où c’est ton travail : la validation. any te ferait
sauter cette étape — et la dette se paierait à l’exécution.
anydit « tais-toi, je sais mieux ».unknowndit « prouve-le ».
Réserve any aux cas vraiment exceptionnels. Pour tout le reste, unknown te
force à transformer l’inconnu en prouvé — exactement là où une frontière doit
arrêter de mentir.
Both mean “I don’t know the type.” But any and unknown are opposites: one
disables the checks, the other strengthens them. Choosing well between the
two means deciding whether you keep TypeScript’s safety net or not.
any: the hole in the type system
An any value accepts everything, and lets you do everything. The compiler stays
silent — including about errors:
let x: any = "hello";
x.toFixed(2); // no compile error… crashes at runtime
x.foo.bar.baz; // no error eitherany is contagious: anything derived from it becomes any too. A single
mistyped value can switch off the guarantees of half your file without you
noticing.
unknown: the honest unknown
unknown also accepts any value as input. But on the way out, it lets you do
nothing until you’ve proven the type:
let x: unknown = "hello";
x.toFixed(2); // ❌ Error: 'x' is of type 'unknown'
if (typeof x === "string") {
x.toUpperCase(); // ✅ here, x is proven to be string
}Same input safety as any, but the compiler forces you to check before using.
The uncertainty is explicit, not swept under the rug.
The practical rule
At your program’s boundaries — a JSON.parse, an API response, a catch (e) —
you receive data whose shape you don’t know. Type it unknown, not any:
async function loadUser(): Promise<User> {
const data: unknown = await res.json();
return parseUser(data); // a function that validates and returns a User
}You keep the honest “I don’t know” of unknown, and you turn it into certainty at
the one place where that’s your job: validation. any would let you skip that step
— and the debt would come due at runtime.
anysays “be quiet, I know better.”unknownsays “prove it.”
Save any for the truly exceptional cases. For everything else, unknown forces
you to turn the unknown into the proven — exactly where a boundary must stop lying.