A type predicate (`param is Type`) lets you write a reusable function that TypeScript treats as a narrowing check, just like built-in `typeof`/`instanceof` guards.
ts
interface Erc20 { symbol: string; decimals: number; }
interface Erc721 { symbol: string; tokenId: string; }
function isErc20(t: Erc20 | Erc721): t is Erc20 {
return "decimals" in t;
}
function describe(t: Erc20 | Erc721): string {
if (isErc20(t)) {
return `${t.symbol} has ${t.decimals} decimals`; // t: Erc20
}
return `${t.symbol} token ${t.tokenId}`; // t: Erc721
}Custom guards are essential when the narrowing logic is more complex than a single `typeof`/`in` check — e.g. validating an unknown JSON payload against an expected shape before treating it as trusted data.