TypeScript Course
TypeScript
/
Intermediate

any vs unknown vs never

Definition

Special types in TypeScript. `any` turns off type checking. `unknown` is a safer `any` that forces you to check the type before using it. `never` represents a state that should never logically occur.

Explain Like I'm New

`any` is turning off the smoke alarm. `unknown` is a suspicious package; you can hold it, but you aren't allowed to open it until you scan it. `never` is an empty black hole; a function that returns `never` means it crashed or runs infinitely.

Real World Example

Using `unknown` for data coming from a 3rd-party API `const data: unknown = fetch(...)`, forcing you to write `if (typeof data === 'string')` before accessing it.

Common Use Cases

  • •Handling dynamic API data (unknown)
  • •Exhaustiveness checking in switch statements (never)
  • •Escaping the type system entirely (any - rarely recommended)

Interactive Example

let danger: any = 5;
danger.toUpperCase(); // TS ignores this. App crashes at runtime.

let mystery: unknown = 5;
// mystery.toUpperCase(); // TS ERROR: Object is of type 'unknown'.

if (typeof mystery === 'string') {
  mystery.toUpperCase(); // Safe! TS now knows it is a string.
}

// never example: Function that throws an error never actually returns a value
function crashApp(msg: string): never {
  throw new Error(msg);
}

Interview Questions

basic

  • Why is using `any` considered bad practice?

intermediate

  • Why is `unknown` safer than `any`?

advanced

  • How do you use `never` for exhaustive `switch` checks?

Flash Cards

Question

Why is unknown safer?

Click to reveal answer
Answer

If `val: any`, TS lets you do `val.toFixed()`. If `val` happens to be a string, your app crashes at runtime. If `val: unknown`, TS throws a compile error if you try to do `val.toFixed()`. It forces you to write `if (typeof val === 'number') val.toFixed()` first.

Question

How do you use never for switch checks?

Click to reveal answer
Answer

If you have a union type `type Role = 'Admin' | 'User'`, and your switch statement checks both, the `default` case should be `const exhaustiveCheck: never = role;`. If someone later adds 'Guest' to the union but forgets to update the switch, TS will throw an error because 'Guest' cannot be assigned to `never`.