Quick Overview
`any` switches the compiler off for that value; `unknown` accepts anything but permits nothing until it is narrowed. That is why `unknown` is the correct type for a parsed JSON response.
When dealing with dynamic data from external APIs or user input, you need a way to represent values of unknown shape. TypeScript provides two types for this: any and unknown.
any (Type Infection)Using any completely turns off type checking for that variable. Worse, any infects any variable it touches, turning off type safety down the chain!
let data: any = JSON.parse('{"score": 100}');
// DANGER: No compile error, but crashes at runtime if 'name' is missing!
data.nonExistentMethod();
const length: number = data.whatever.foo.bar; // Infects entire pipeline!
unknownThe unknown type represents any value, but TypeScript forces you to perform type checking or narrowing before you can access properties or invoke methods on it:
let safeData: unknown = JSON.parse('{"score": 100}');
// safeData.nonExistentMethod(); // Error: Object is of type 'unknown'!
// Must narrow type first!
if (typeof safeData === "object" && safeData !== null && "score" in safeData) {
console.log("Score is valid!");
}
[ Top Type: any ] ──> Bypasses all type checks (Unsafe)
[ Top Type: unknown ] ──> Holds any value, requires narrowing (Safe)
any: Using any defeats the primary purpose of using TypeScript. Configure noImplicitAny: true in tsconfig.json to block unannotated any variables!Always prefer unknown over any when handling external dynamic inputs. Next, let's explore the never type and Exhaustiveness Checking!
TypeScript erases entirely at build time, so a `string` annotation produces no runtime check whatsoever. A value arriving from an API is whatever the server actually sent, regardless of what the annotation claims.
`let x = "GET"` infers `string` because the binding can change; `const x = "GET"` infers the literal `"GET"`. That widening rule is why object properties need `as const` to stay narrow.
`string[]` is any number of strings; `[string, number]` is exactly two, in that order. `readonly` removes the mutating methods at compile time, so `push` becomes a type error rather than a runtime surprise.