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