EasyType System📖 Theory Question

What are type guards and how do you create custom ones?

💡

Hint

Narrowing the type in a branch — typeof, instanceof, in operator, or a user-defined predicate function

Full Answer

Type guards narrow a broad type to a more specific one within a conditional block.

Built-in type guards:

function process(val: string | number | null) {
  if (typeof val === 'string') { /* val is string */ }
  if (typeof val === 'number') { /* val is number */ }
  if (val !== null) { /* val is string | number */ }
}

// instanceof — for class instances
function handleEvent(e: MouseEvent | KeyboardEvent) {
  if (e instanceof KeyboardEvent) {
    console.log(e.key); // safe
  }
}

// in operator — property existence check
type Cat = { meow(): void };
type Dog = { bark(): void };
function speak(animal: Cat | Dog) {
  if ('meow' in animal) animal.meow();
  else animal.bark();
}

User-defined type guard — a function returning val is T:

interface User { id: number; name: string; }

// The return type "val is User" is the type predicate
function isUser(val: unknown): val is User {
  return (
    typeof val === 'object' &&
    val !== null &&
    'id' in val &&
    'name' in val &&
    typeof (val as User).id === 'number' &&
    typeof (val as User).name === 'string'
  );
}

// Usage — TypeScript now knows it's a User after the check
const data: unknown = fetchJSON();
if (isUser(data)) {
  console.log(data.name); // safe — TypeScript trusts your predicate
}
💡 Type predicates (val is T) are a contract you make with TypeScript. If your implementation is wrong, TypeScript won't catch it — always thoroughly validate all expected fields.

More Type System Questions

EasyWhat is type inference in TypeScript and when does it kick in?EasyWhat is the difference between any, unknown, and never in TypeScript?EasyWhat are type assertions and when should you use them?EasyWhat is structural typing (duck typing) in TypeScript?

Practice this in a timed sprint →

5 free questions, no signup required

⚡ Start Sprint