DEV Community

Cover image for How to Use the any Type and When to Avoid It
Krunal Kanojiya
Krunal Kanojiya

Posted on

How to Use the any Type and When to Avoid It

TLDR

any is a special TypeScript type that turns off all type checking for a variable. It lets you assign any value and call any method without errors. This makes it feel helpful but it quietly breaks the safety TypeScript gives you. Avoid any in almost every case. Use unknown when you do not know the type yet. Only use any as a last resort when migrating old JavaScript code or working with untyped third-party libraries.


What is the any Type?

any is a type that tells TypeScript to stop checking a variable. Once you mark something as any, TypeScript lets you do anything with it.

You can assign a string. You can assign a number. You can call methods that do not exist. TypeScript will not say a word. It just trusts you to get it right.

let value: any = "hello";
value = 42;         // OK
value = true;       // OK
value = { x: 1 };  // OK
value = null;       // OK
value();            // OK — TypeScript does not check this
value.foo.bar.baz;  // OK — TypeScript does not check this either
Enter fullscreen mode Exit fullscreen mode

All of those lines compile without error. But some of them will crash hard at runtime.


How any Disables Type Checking

The core problem with any is simple. TypeScript checks types to catch bugs. any turns that checking off. It is like buying a smoke detector and then removing the battery.

Here is what normally happens with a typed variable:

let name: string = "Alice";
name.toUpperCase(); // OK
name.push("Bob");   // Error: Property 'push' does not exist on type 'string'.
Enter fullscreen mode Exit fullscreen mode

TypeScript catches the mistake. Now compare that with any:

let name: any = "Alice";
name.toUpperCase(); // OK at compile time
name.push("Bob");   // Also OK at compile time — but crashes at runtime
Enter fullscreen mode Exit fullscreen mode

TypeScript sees any and stops checking. The bug gets through to production.


Two Ways any Appears in Your Code

Explicit any

This is when you write any yourself on purpose:

let data: any = fetchSomeData();
let input: any;
function process(value: any): any { ... }
Enter fullscreen mode Exit fullscreen mode

You chose to use any. TypeScript respects that and skips type checking.

Implicit any

This is when TypeScript cannot figure out the type and defaults to any quietly:

// TypeScript cannot infer the type of 'item' here
function logItem(item) {
  console.log(item);
}
Enter fullscreen mode Exit fullscreen mode

Without a type annotation, TypeScript gives item the type any if noImplicitAny is off. This is more dangerous because it is silent.

The noImplicitAny flag (included in strict: true) stops this from happening:

function logItem(item) {
// Error: Parameter 'item' implicitly has an 'any' type.
}
Enter fullscreen mode Exit fullscreen mode

With the error in place, you are forced to add a proper type:

function logItem(item: string): void {
  console.log(item);
}
Enter fullscreen mode Exit fullscreen mode

Why any is Dangerous

Problem 1: Errors reach runtime instead of compile time

function getFirstChar(value: any): string {
  return value[0]; // TypeScript is fine with this
}

getFirstChar(123);
// No compile error
// But at runtime: 1 (not a crash here, but wrong behavior)

getFirstChar(null);
// No compile error
// Crashes at runtime: Cannot read properties of null
Enter fullscreen mode Exit fullscreen mode

Problem 2: any spreads to other variables

When you assign an any value to another variable, that variable also becomes any. This is called any infection. One any can quietly spread through your whole codebase.

let raw: any = getData();

let name = raw.name;       // name is now any
let age = raw.age;         // age is now any
let city = raw.address.city; // city is now any

// TypeScript checks none of these
age.toUpperCase();          // No error — but crashes at runtime if age is a number
Enter fullscreen mode Exit fullscreen mode

Problem 3: You lose IDE support

TypeScript powers your editor's autocomplete, hover hints, and refactoring tools. When a variable is any, none of that works. You lose the benefits that make TypeScript worth using.

let user: any = getUser();
user. // No autocomplete suggestions here
Enter fullscreen mode Exit fullscreen mode

Compare that with a typed variable:

let user: { name: string; age: number } = getUser();
user. // Editor shows: name, age
Enter fullscreen mode Exit fullscreen mode

Problem 4: Bugs survive code reviews

Type errors show up in CI/CD pipelines and in your editor. They are hard to miss. But runtime crashes from any only show up when users hit that code path. They are much harder to catch.


The any Infection Example

Here is a realistic example of how any spreads:

// Step 1: One any at the boundary
const response: any = await fetch("/api/user").then(r => r.json());

// Step 2: Everything from it is also any
const userId = response.id;       // any
const userName = response.name;   // any
const userEmail = response.email; // any

// Step 3: Functions that use these values lose type safety too
function sendWelcomeEmail(email: any): void {
  // email is any, no checks inside this function either
}

// Step 4: The bug is invisible
sendWelcomeEmail(userId); // Wrong value passed — no error
Enter fullscreen mode Exit fullscreen mode

None of these lines produce a TypeScript error. But the last line passes an ID where an email is expected. In production, users get a broken welcome email at best, or a crash at worst.


When is any Actually Okay to Use?

There are a small number of situations where any is an acceptable choice. Be honest with yourself about which category you are in before reaching for it.

Situation Is any Okay? Better Alternative
Migrating a JS file to TS step by step Yes, temporarily Add types file by file
Third-party library with no type definitions Sometimes Write a .d.ts file or use unknown
Truly unknown JSON data from an API Temporarily Use unknown + type guard
You do not want to figure out the type No Spend the time finding the right type
Prototype or throwaway script Acceptable Not needed for prod code
You are in a hurry No Technical debt that bites later

The Right Alternative: unknown

unknown is the safe version of any. You can assign anything to an unknown variable just like any. But TypeScript will not let you use the value until you check its type first.

let value: unknown = getData();

// This does not compile with unknown
value.toUpperCase();
// Error: 'value' is of type 'unknown'.

// You must check the type first
if (typeof value === "string") {
  value.toUpperCase(); // Now TypeScript knows it is a string — safe
}
Enter fullscreen mode Exit fullscreen mode

Here is a side-by-side comparison:

any unknown
Can assign any value Yes Yes
TypeScript checks usage No Yes, after a type check
Autocomplete works No Yes, after narrowing
Crashes at runtime Possible Much less likely
Recommended Almost never When type is truly unknown

Practical example: Handling API responses safely

With any (unsafe):

async function getUser(): Promise<any> {
  const response = await fetch("/api/user");
  return response.json(); // Returns any
}

const user = await getUser();
console.log(user.name.toUpperCase()); // No error, but crashes if name is missing
Enter fullscreen mode Exit fullscreen mode

With unknown (safe):

async function getUser(): Promise<unknown> {
  const response = await fetch("/api/user");
  return response.json();
}

const user = await getUser();

// Must check the shape before using it
if (
  typeof user === "object" &&
  user !== null &&
  "name" in user &&
  typeof (user as { name: unknown }).name === "string"
) {
  console.log((user as { name: string }).name.toUpperCase()); // Safe
}
Enter fullscreen mode Exit fullscreen mode

Tip: For real projects, use a library like Zod to validate API responses instead of writing manual type guards. It is faster and more reliable.


How to Handle any When Migrating JavaScript Code

When you are moving a JavaScript project to TypeScript, you will see any everywhere. That is okay as a starting point. The goal is to replace it over time.

Use this step-by-step approach:

// Step 1: Start with any to get the file compiling
function processOrder(order: any): any {
  return order.total * 1.1;
}

// Step 2: Add a type for the input first
type Order = {
  id: number;
  total: number;
};

function processOrder(order: Order): any {
  return order.total * 1.1;
}

// Step 3: Add the return type
function processOrder(order: Order): number {
  return order.total * 1.1;
}
Enter fullscreen mode Exit fullscreen mode

Go one function at a time. Do not try to fix everything at once.


How to Prevent any With ESLint

Setting noImplicitAny: true stops TypeScript from adding any silently. But it does not stop you from writing any yourself.

For that, use the @typescript-eslint/no-explicit-any rule:

// .eslintrc.json
{
  "rules": {
    "@typescript-eslint/no-explicit-any": "error"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now this will fail your lint check:

let data: any = fetch(); // ESLint error: Unexpected any. Specify a different type.
Enter fullscreen mode Exit fullscreen mode

This is the best way to keep any out of a team codebase. The linter enforces it for everyone automatically.


@ts-ignore and @ts-expect-error: Related Escape Hatches

Two comment directives work like any but at the line level. They suppress TypeScript errors on the next line.

// @ts-ignore
const result = doSomethingBroken(); // TypeScript ignores errors on this line

// @ts-expect-error
const result2 = doSomethingBroken(); // Same, but gives an error if there is NO error
Enter fullscreen mode Exit fullscreen mode

The difference between the two:

Directive What it does
// @ts-ignore Suppresses the error. No feedback if error disappears.
// @ts-expect-error Suppresses the error. Gives a new error if the error is fixed.

Prefer @ts-expect-error over @ts-ignore. It will alert you when the suppression is no longer needed so you can clean it up.

Use both of these as rarely as possible. They hide real problems.


any vs unknown vs never: Quick Comparison

Type What You Can Assign To It What You Can Do With It
any Anything Anything — no checks
unknown Anything Nothing until you narrow the type
never Nothing Nothing — it is an impossible type
let a: any = "hello";
a.toUpperCase();  // OK — no checking

let b: unknown = "hello";
b.toUpperCase();  // Error — must narrow first
if (typeof b === "string") {
  b.toUpperCase(); // OK — narrowed to string
}

let c: never;
c = "hello"; // Error — nothing can be assigned to never
Enter fullscreen mode Exit fullscreen mode

Common Mistakes with any

Mistake 1: Using any for JSON responses

// Bad
const data: any = await response.json();

// Better
const data: unknown = await response.json();
// Then validate the shape before using it
Enter fullscreen mode Exit fullscreen mode

Mistake 2: Spreading any through utility functions

// Bad: input and return are both any, spreading infection
function transform(input: any): any {
  return input.value;
}

// Good: types are explicit
type InputData = { value: string };
function transform(input: InputData): string {
  return input.value;
}
Enter fullscreen mode Exit fullscreen mode

Mistake 3: Casting to any to silence errors

// Bad: hiding a real type mismatch
const user = getUser() as any;
user.nonExistentMethod(); // Compiles, crashes at runtime

// Good: fix the actual type issue
const user: User = getUser();
Enter fullscreen mode Exit fullscreen mode

Mistake 4: Using any[] for arrays

// Bad
const items: any[] = [1, "two", true];

// Better: use a union type
const items: (number | string | boolean)[] = [1, "two", true];

// Or, if all items are the same type
const scores: number[] = [1, 2, 3];
Enter fullscreen mode Exit fullscreen mode

FAQ

Q: Is any the same as not using TypeScript at all?
Almost, yes. A variable typed as any gets zero type checking. Using any everywhere is the same as writing plain JavaScript with extra steps.

Q: When should I use any vs unknown?
Use unknown when you do not know the type yet but want TypeScript to keep checking how you use the value. Use any only as a last resort during migration or when a library gives you no other choice.

Q: Can I use any in a production codebase?
You can, but you should not. Every any is a place where type safety breaks down and bugs can hide. Use ESLint to ban it and replace it with proper types or unknown.

Q: Does noImplicitAny ban all any?
No. noImplicitAny only stops TypeScript from silently adding any when it cannot infer a type. It does not stop you from writing any yourself. Use the @typescript-eslint/no-explicit-any ESLint rule to ban explicit any too.

Q: What happens to any in the compiled JavaScript?
Nothing. Like all types, any is removed at compile time. It is only a TypeScript concept and has no effect on the JavaScript output.

Q: Is it okay to use any in test files?
It is more acceptable in test files than in production code. But you should still prefer proper types. Typed tests catch more bugs and are easier to maintain.


What You Learned

  • any turns off all type checking for a variable and lets you assign or do anything with it
  • TypeScript defaults to implicit any when it cannot infer a type. noImplicitAny: true stops this
  • any is dangerous because errors skip compile time and reach runtime instead
  • any spreads to other variables. One any can infect a whole chain of code
  • unknown is the safe alternative. You must check the type before using an unknown value
  • Use any only for JS migration or untyped third-party libraries, and replace it as soon as you can
  • Use @typescript-eslint/no-explicit-any to ban any from your team's codebase
  • Prefer @ts-expect-error over @ts-ignore when you must suppress a TypeScript error

Sources: TypeScript Handbook — Everyday Types | typescript-eslint — no-explicit-any | TypeScript TSConfig Reference

Top comments (1)

Collapse
 
frank_signorini profile image
Frank

I often find myself reaching for `any