Built-in checks (typeof, in, instanceof) can't express "this object matches my interface". A user-defined type guard can. Give a function the return type paramName is Type, a type predicate. When a call returns true, TypeScript narrows the argument to Type in the true branch, and removes Type from it in the false branch.
An assertion function (TS 3.7) narrows by throwing instead of returning false. There are two signatures:
asserts value is T: after the call returns,valueisT.asserts condition: after the call returns, the argument expression is truthy (Node'sassertis typed this way).
Rules and traps:
- The body is not checked. The handbook says explicit predicates are "no safer than a type assertion". A predicate that returns
truefor the wrong values silently corrupts every call site. - If-and-only-if. Returning
falsemeans the value is notT.s is stringimplemented as!!sis wrong:""is a string that returnsfalse. - The predicate type must be assignable to the parameter type:
n: numberwithn is stringis error TS2677. - Assertion calls need an explicit annotation. The call target must be declared with an explicit type, so a bare
const assertStr = (v: unknown): asserts v is string => {...}fails at the call site with TS2775. Use a function declaration, or annotate the const. - Inferred predicates (TS 5.5). A function with no return annotation, one
return, no parameter mutation, and a boolean expression tied to a refinement infersx is T.[1, undefined, 3].filter(n => n !== undefined)becomesnumber[].
For untrusted unknown data, write the guard once at the boundary.