0Pricing
TypeScript Academy · Lesson

Assertions vs Type Guards

Prefer runtime checks over assertions where possible.

Assertions vs Type Guards is a free TypeScript Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Two Ways to Convince the Compiler

When the compiler doesn't know a value's exact type, you have two options: assert it (claim the type) or guard it (prove the type at runtime). They look similar but offer very different safety.

function viaAssert(v: unknown): number {
  return (v as number) + 1; // claim
}
function viaGuard(v: unknown): number {
  return typeof v === 'number' ? v + 1 : 0; // prove
}
console.log(viaAssert(5), viaGuard(5), viaGuard('x'));

Assertions Don't Verify

An assertion is a promise with no enforcement. If you're wrong, the bug slips through to runtime. Assertions trade safety for convenience.

const v: unknown = 'hello';
const n = v as number;
console.log(n.toFixed(2)); // runtime error: toFixed is not a function

Type Guards Verify at Runtime

A type guard actually checks the value. If the check passes, both you and the compiler know the type is correct — there's a real runtime test backing the narrowing.

function toFixed2(v: unknown): string {
  if (typeof v === 'number') return v.toFixed(2);
  return 'N/A';
}
console.log(toFixed2(3.14159), toFixed2('hi'));

Custom Type Guard Functions

Encapsulate complex checks in a reusable guard returning value is T. The whole codebase benefits from one well-tested validation.

type Email = { address: string };
function isEmail(v: unknown): v is Email {
  return typeof v === 'object' && v !== null &&
    'address' in v && typeof (v as any).address === 'string';
}
console.log(isEmail({ address: 'a@b.com' }), isEmail(null));

Guards Compose and Reuse

Because guards are ordinary functions, you can combine them, test them, and reuse them. Assertions, by contrast, are scattered claims that can't be validated centrally.

function isString(v: unknown): v is string { return typeof v === 'string'; }
function isNonEmpty(v: unknown): v is string {
  return isString(v) && v.length > 0;
}
console.log(isNonEmpty('hi'), isNonEmpty(''));

Assertion Functions With asserts

TypeScript also offers assertion functions. Their return annotation uses the asserts keyword. If the function returns normally, the compiler narrows the argument from that point on; if the condition fails, it throws.

function assertNumber(v: unknown): asserts v is number {
  if (typeof v !== 'number') throw new Error('not a number');
}
function use(v: unknown): number {
  assertNumber(v); // after this line, v is number
  return v * 2;
}
console.log(use(21));

asserts vs value is

A value is T guard returns a boolean you branch on. An asserts value is T function throws on failure and narrows for the rest of the scope. Both are runtime-backed, unlike a plain as.

function assertDefined<T>(v: T): asserts v is NonNullable<T> {
  if (v === null || v === undefined) throw new Error('missing');
}
const maybe: string | null = 'ok';
assertDefined(maybe);
console.log(maybe.length); // narrowed to string

Generic Assertion Helpers

Assertion functions make great reusable preconditions. A single assert(condition) helper can guard invariants throughout your code, throwing early on violations.

function assert(cond: unknown, msg: string): asserts cond {
  if (!cond) throw new Error(msg);
}
function half(n: number): number {
  assert(n % 2 === 0, 'must be even');
  return n / 2;
}
console.log(half(8));

Comparing Safety

Ranking from safest to riskiest: type guards and assertion functions (runtime-checked) sit above plain as assertions (unchecked), which sit above double assertions (actively misleading). Reach for the safest tool that fits.

// Safe: guard
function safe(v: unknown) {
  return typeof v === 'string' ? v.trim() : '';
}
console.log(safe('  hi  '));

Choosing the Right Tool

Use a type guard when you branch on the type. Use an assertion function when a precondition must hold or execution should stop. Use as only when narrowing is impossible (e.g. DOM specialization).

function getInput(v: unknown): asserts v is string {
  if (typeof v !== 'string') throw new Error('expected string');
}
const raw: unknown = 'name';
getInput(raw);
console.log(raw.toUpperCase());

Runtime Checks Win

The recurring theme of this course: prefer runtime checks over assertions. Guards and assertion functions give you both compile-time types and runtime safety. Assertions give you only a claim.

function parsePort(v: unknown): number {
  if (typeof v === 'number' && Number.isInteger(v)) return v;
  throw new Error('invalid port');
}
console.log(parsePort(8080));

Quick Check

Test your understanding of assertions vs type guards.

Recap: Assertions vs Guards

You learned that:

  • Type guards (value is T) prove a type at runtime and let you branch.
  • Assertion functions (asserts value is T) throw on failure and narrow afterward.
  • Plain as assertions only claim a type — no runtime safety.
  • Prefer runtime-checked tools; reserve assertions for cases narrowing can't handle.

Next course: optional chaining and nullish coalescing.

function isPositive(v: unknown): v is number {
  return typeof v === 'number' && v > 0;
}
console.log(isPositive(5), isPositive(-1));

Frequently asked questions

Is the “Assertions vs Type Guards” lesson free?

Yes — the full text of “Assertions vs Type Guards” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “Assertions vs Type Guards”?

Prefer runtime checks over assertions where possible. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Assertions vs Type Guards” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The as Keyword for Type Assertions
  2. Non-null Assertion Operator
  3. Double Assertions and Their Risks
  4. Assertions vs Type Guards
← Back to TypeScript Academy