Learning Guides
Menu

Working with any

4 min readEffective TypeScript

Working with any

any is TypeScript's escape hatch. It's sometimes necessary, but it disables the type system. This chapter shows how to contain any so you keep the benefits of TypeScript.

Why any Is Dangerous

When you use any, everything becomes legal:

TYPESCRIPT
let value: any = "hello";
value = 42;
value.toFixed(); // No error, might explode at runtime
value.notAFunction(); // No error, runtime crash

The problem is contagious: any tends to spread across your codebase, making more and more of it untyped.

Warning

Think of any like "unchecked" code. Allow it only in the smallest, most isolated parts of your app.

Item 40: Use any Only at Boundaries

The best place for any is at external boundaries where you truly don’t control the data: API responses, localStorage, DOM access, third‑party libraries.

TYPESCRIPT
// Boundary: JSON from API
async function fetchUserRaw(id: string): Promise<any> {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}
 
// Core: convert to typed structure
async function fetchUser(id: string): Promise<User> {
  const data = await fetchUserRaw(id);
  return parseUser(data); // runtime validation
}

Boundary Pattern

TYPESCRIPT
// Boundary function returns unknown
async function getSettingsRaw(): Promise<unknown> {
  const raw = localStorage.getItem('settings');
  return raw ? JSON.parse(raw) : {};
}
 
// Core function returns typed Settings
async function getSettings(): Promise<Settings> {
const data = await getSettingsRaw();
if (!isSettings(data)) {
return getDefaultSettings();
}
return data;
}
 

Item 41: Prefer unknown Over any

unknown forces you to check types before use:

TYPESCRIPT
function parseConfig(input: unknown): Config {
  if (!isConfig(input)) throw new Error('Invalid config');
  return input;
}

Why unknown Helps

  • You can still accept anything.
  • You must validate before using it.
  • It keeps type safety in core code.

Item 42: Keep any in Small, Localized Scopes

If you must use any, isolate it:

TYPESCRIPT
function parseLoose(input: string): string {
  const data: any = JSON.parse(input);
  return String(data.name ?? "Unknown");
}

Only the one function is untyped; everything else stays safe.

Item 43: Use Runtime Validation Instead of as

Type assertions do not validate:

TYPESCRIPT
const data = JSON.parse('{"age":"not a number"}') as { age: number };
data.age.toFixed(); // Runtime crash

Use runtime validation:

TYPESCRIPT
function isUser(value: unknown): value is User {
  return typeof value === "object" && value !== null && "email" in value;
}

Item 44: Use @ts-expect-error Instead of @ts-ignore

TYPESCRIPT
// @ts-expect-error: legacy API returns malformed date
const date = new Date(legacyDateString);

If the error disappears, your build fails, so you know to remove the comment.

Item 45: Turn On Compiler Flags That Prevent Hidden any

These options catch any where it sneaks in:

JSON
{
  "compilerOptions": {
    "noImplicitAny": true,
    "noImplicitThis": true,
    "useUnknownInCatchVariables": true
  }
}

Item 46: Convert anyunknown in Legacy Code

This is a safe first step that doesn’t change runtime behavior:

TYPESCRIPT
let data: any = getLegacyData();
// Safer:
let data: unknown = getLegacyData();

Then add guards as you touch the code.

Item 47: Wrap Untyped Libraries

If a library has no types, create a tiny typed adapter:

TYPESCRIPT
import legacyLib from "legacy-lib";
 
export function parseCustomer(input: string): Customer {
  const raw = legacyLib.parse(input) as unknown;
  if (!isCustomer(raw)) throw new Error("Invalid");
  return raw;
}

This makes the rest of your app safe even if the library is not.

Common Scenarios

Scenario: API Response With Unstable Shape

TYPESCRIPT
async function getOrders(): Promise<Order[]> {
  const data: unknown = await fetch("/api/orders").then((r) => r.json());
  if (!Array.isArray(data)) return [];
  return data.filter(isOrder);
}

Scenario: Dynamic JSON From LocalStorage

TYPESCRIPT
function loadTheme(): Theme {
  const value = localStorage.getItem("theme");
  return value === "dark" || value === "light" ? value : "dark";
}

Key Takeaways

  1. Use any only at boundaries.
  2. Prefer unknown and runtime validation.
  3. Keep unsafe code isolated.
  4. Use @ts-expect-error for intentional escapes.
  5. Use compiler flags to catch hidden any.
  6. Wrap untyped libraries with typed adapters.

Next: writing and using type declarations effectively.