Assertion vs throw
- TypeScript course
- Advanced
- Lesson 43/57
- 4 min
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
// 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ırSample 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"));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
function process(v: unknown): string {
assertString(v);
return ____;
}
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 |