Careeroza
User-defined Type Guards
Functions That Narrow: x is T
A function whose return type is value is T is a type guard. When it returns true, TypeScript narrows the argument to T in the calling code.
Example
type Product = { id: number; name: string; price: number };
function isProduct(x: unknown): x is Product {
return (
typeof x === "object" && x !== null &&
"id" in x && typeof x.id === "number" &&
"name" in x && typeof x.name === "string" &&
"price" in x && typeof x.price === "number"
);
}
const payload: unknown[] = JSON.parse('[{"id":1,"name":"Kettle","price":1299},{"id":"2","name":"Bad"}]');
for (const item of payload) {
if (isProduct(item)) console.log("OK:", item.name, item.price);
else console.log("Skipped invalid item:", JSON.stringify(item));
}Output
OK: Kettle 1299
Skipped invalid item: {"id":"2","name":"Bad"}Filtering with a Type Guard
Example
Passing a guard to filter narrows the resulting array type. Since TypeScript 5.5, simple arrow functions like x => x !== null are inferred as guards automatically.
type Coupon = { code: string; percent: number };
const coupons: (Coupon | null)[] = [{ code: "NEW50", percent: 50 }, null, { code: "SAVE10", percent: 10 }];
const valid = coupons.filter((c): c is Coupon => c !== null); // Coupon[]
console.log(valid.map((c) => c.code));
const inferred = coupons.filter((c) => c !== null); // also Coupon[] in TS 5.5+
console.log(inferred.reduce((max, c) => Math.max(max, c.percent), 0));Output
[ 'NEW50', 'SAVE10' ] 50