Working with any
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:
let value: any = "hello";
value = 42;
value.toFixed(); // No error, might explode at runtime
value.notAFunction(); // No error, runtime crashThe 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.
// 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
// 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:
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:
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:
const data = JSON.parse('{"age":"not a number"}') as { age: number };
data.age.toFixed(); // Runtime crashUse runtime validation:
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
// @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:
{
"compilerOptions": {
"noImplicitAny": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true
}
}Item 46: Convert any → unknown in Legacy Code
This is a safe first step that doesn’t change runtime behavior:
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:
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
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
function loadTheme(): Theme {
const value = localStorage.getItem("theme");
return value === "dark" || value === "light" ? value : "dark";
}Key Takeaways
- Use
anyonly at boundaries. - Prefer
unknownand runtime validation. - Keep unsafe code isolated.
- Use
@ts-expect-errorfor intentional escapes. - Use compiler flags to catch hidden
any. - Wrap untyped libraries with typed adapters.
Next: writing and using type declarations effectively.