TypeScript
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();
}
Exercise 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")).
Show example solution
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"));
Test yourself
-
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
- It makes all types any
Show answer
It makes the narrowing logic reusable — 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.
-
Assertion instead of manual throw
function process(v: unknown): string {
assertString(v);
return ____;
}
Show answer
function process(v: unknown): string {
assertString(v);
return v.toUpperCase();
}
-
Assertion vs throw parts
- if (!x) throw ...
- manual narrowing
- assertString(v)
- reusable narrowing
- asserts x is T
- type-level narrowing
- throw new Error
- runtime stop
Next lesson: Summary - Assertion functions