dev3 ·
I get 'Property x does not exist on type string | number' and 'Object is of type unknown' in catch blocks. How do type guards and narrowing work?
0
DEV3 Developer Forum
Every post is reviewed first. Usually reviewed within 24 hours.
I get 'Property x does not exist on type string | number' and 'Object is of type unknown' in catch blocks. How do type guards and narrowing work?
TypeScript narrows a type inside a block when it can prove something from a check.
function f(v: string | number | null) {
if (v === null) return; // null removed
if (typeof v === 'string') {
v.toUpperCase(); // string here
} else {
v.toFixed(2); // number here
}
}
if (value instanceof Date) { value.getTime(); }
if ('radius' in shape) { shape.radius; } // `in` narrows unions of objects
if (Array.isArray(x)) { x.length; }
type Result =
| { ok: true; data: string }
| { ok: false; error: Error };
function show(r: Result) {
if (r.ok) return r.data; // narrowed by the literal `ok`
return r.error.message;
}
Add an exhaustive check:
function assertNever(x: never): never { throw new Error('Unexpected: ' + x); }
Call it in the final default of a switch and you get a compile error when a new variant is added.
function isUser(x: unknown): x is { id: string; name: string } {
return typeof x === 'object' && x !== null && 'id' in x && 'name' in x;
}
try { ... } catch (e) { // e is unknown with useUnknownInCatchVariables (strict)
const msg = e instanceof Error ? e.message : String(e);
}
Use unknown for external data (JSON, API responses) and validate with a schema library such as zod rather than casting with as.
as assertions silence the compiler but do not check anything at runtime.let variables that might change; use const.Object.keys(obj) returns string[], not keyof typeof obj, by design.The JSON to TypeScript converter can generate interfaces from sample responses.