any
Disables type checking for a value, allowing any operation and any assignment.
let obj: any = { x: 0 };- Added in TypeScript 1.0
Errors
Nothing at compile time — that is the point. Errors from an any value surface only at runtime.
Changelog
- PHP 2.0noImplicitAny became part of the strict family, so implicit any from an un-annotated parameter is reported under strict.
- PHP 3.0unknown was added as the safe counterpart; anything assignable to any is also assignable to unknown, but unknown blocks operations until narrowed.
- PHP 4.0Catch clause variables can be typed unknown instead of any via useUnknownInCatchVariables (default under strict from 4.4).
any is the escape hatch. Annotate a value any and the checker stops looking at it: you can read properties that do not exist, call it like a function, index it, and assign it to a variable of any other type without a single error.
Why it is dangerous
It spreads in both directions. Every expression derived from an any is itself any, so one annotation near the top of a call chain quietly erases checking everywhere below it. And it flows out: assigning an any to a number parameter is permitted, so a string can arrive at a function that has been told it will receive a number. Nothing warns you until the value misbehaves at runtime.
When to reach for it
- Porting a large JavaScript file that has to compile today and be typed later.
- A genuinely dynamic boundary you will validate by hand anyway.
In almost every other case unknown is the type you actually wanted: it accepts exactly the same inputs, but refuses to let you use the value until you have narrowed it. Turn on noImplicitAny so parameters TypeScript cannot infer become errors rather than silent holes.
Example
When to use it
- Compiling a legacy JavaScript file unchanged while you add types module by module
- Wrapping a dynamically shaped third-party payload before you write a validator for it
- Silencing a known-wrong library type temporarily behind a single, commented annotation
Frequently asked questions
What is the difference between any and unknown in TypeScript?
Both accept every value, but `unknown` refuses every operation until you narrow it, while `any` allows all of them. `unknown` is assignable only to `unknown` and `any`; `any` is assignable to anything, which is how bad values leak into typed code. Prefer `unknown` at input boundaries and narrow with `typeof`, `instanceof`, or a type predicate.
How do I fix "Parameter implicitly has an 'any' type"?
Annotate the parameter with a real type — the error means `noImplicitAny` is on and TypeScript could not infer one. For a callback, give the surrounding function a contextual type so the parameter is inferred instead. Setting the parameter to `any` explicitly also silences it, but keeps the hole; `unknown` plus a narrowing check is usually the correct fix.
Is it ever okay to use any?
Yes, in narrow, deliberate places: an incremental JavaScript migration, or a single annotation working around a wrong third-party type. Keep it to one expression and convert to a real type immediately, because `any` propagates through every derived expression. Anywhere you just need "accepts anything", use `unknown`.
More examples
Containing any at the boundary
`leaky.name` prints undefined even though `leaky` is typed `Session`: assigning an `any` skipped every check, so the wrong shape was accepted. `toSession` does the same job but returns `null` for the malformed input, which is the behaviour the type system can actually rely on afterwards.
// A value arriving from outside your types.
const payload: any = { user: { name: "Ada" }, role: "admin" };
interface Session { name: string; role: "admin" | "guest" }
// Bad: any flows straight into typed code, unchecked.
const leaky: Session = payload;
// Better: convert once, at one place, with a real check.
function toSession(input: any): Session | null {
const name = input?.user?.name;
const role = input?.role;
if (typeof name !== "string") return null;
if (role !== "admin" && role !== "guest") return null;
return { name, role };
}
console.log(leaky.name); // undefined — the annotation never checked anything
console.log(toSession(payload)); // { name: 'Ada', role: 'admin' }
console.log(toSession({ role: 1 })); // nullany destroys generic inference
The first call keeps `number`, so `.toFixed` is checked and `.toUpperCase` would be rejected by tsc. Forcing `T` to `any` removes the check entirely: `loose.toUpperCase` compiles and is simply `undefined` at runtime. The last line shows `any[]` collapses element checking too, printing `[ 'number', 'string', 'boolean' ]`.
function first<T>(items: T[]): T {
return items[0];
}
const typed = first([1, 2, 3]); // T inferred as number
const loose = first<any>([1, 2, 3]); // T is any
console.log(typed.toFixed(1)); // "1.0"
// typed.toUpperCase() // Error: Property 'toUpperCase' does not exist on type 'number'.
console.log(typeof loose.toUpperCase); // "undefined" — no compile error, no method
const mixed: any[] = [1, "two", true];
console.log(mixed.map((v) => typeof v));
Discussion