CodeBlanks Logo Icon CodeBlanks

Assertion vs throw

Learn the difference between assertion and throwing.

Assertion vs throw

The difference between an assertion function and a manual throw is that the assertion function performs type-level narrowing. if (!x) throw new Error() also narrows manually, but an assertion function makes this logic reusable and the call is a single line.

// Manual throw narrowing
function manual(v: unknown): string {
  if (typeof v !== "string") throw new Error("not string");
  return v.toUpperCase();
}

// Assertion function narrowing
function assertString(x: unknown): asserts x is string {
  if (typeof x !== "string") throw new Error("not string");
}

function withAssert(v: unknown): string {
  assertString(v);
  return v.toUpperCase();
}

Reusability

When the same validation is needed in multiple places, defining an assertion function prevents repetition. Instead of writing if (...) throw ... at each call site, a single function is called; the error message and check are kept in one place.

function assertString(x: unknown): asserts x is string {
  if (typeof x !== "string") throw new Error("not string");
}

// Reused:
function upper(v: unknown): string {
  assertString(v);
  return v.toUpperCase();
}

function lower(v: unknown): string {
  assertString(v);
  return v.toLowerCase();
}

Practice Clean narrowing with assertions

Define an assertString(x: unknown): asserts x is string function (with throw new Error("not string") when typeof x !== "string"). Write an upper(v: unknown): string function: call assertString(v), then return v.toUpperCase(). Write a lower(v: unknown): string function: call assertString(v), then return v.toLowerCase(). Print results via console.log(upper("hello")) and console.log(lower("WORLD")).

Starter code

index.ts
// assertString fonksiyonunu tanımla (asserts x is string, throw ile)

// upper fonksiyonunu assertString ile yaz

// lower fonksiyonunu assertString ile yaz

// upper("hello") ve lower("WORLD") sonuçlarını yazdır

Sample solution

index.ts
function assertString(x: unknown): asserts x is string {
  if (typeof x !== "string") {
    throw new Error("not string");
  }
}

function upper(v: unknown): string {
  assertString(v);
  return v.toUpperCase();
}

function lower(v: unknown): string {
  assertString(v);
  return v.toLowerCase();
}

console.log(upper("hello"));
console.log(lower("WORLD"));

Expected output

HELLO
world

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What advantage does an assertion function provide over a manual throw?

  • It is faster at runtime
  • It does not throw errors
  • It makes the narrowing logic reusable Correct answer
  • It makes all types any

Explanation: An assertion function encapsulates the throw and narrowing logic in a single reusable function; instead of writing if-throw at each call site, a single-line call is enough.

2 Assertion instead of manual throw

Question
function process(v: unknown): string {
  assertString(v);
  return ____;
}
Answer
function process(v: unknown): string {
  assertString(v);
  return v.toUpperCase();
}

Explanation: After calling assertString(v), v is narrowed to string so v.toUpperCase() can be written directly; no re-check or cast is needed.

3 Assertion vs throw parts

Term Meaning
if (!x) throw ... manual narrowing
assertString(v) reusable narrowing
asserts x is T type-level narrowing
throw new Error runtime stop

All lessons in Advanced