Functions
Any function with typed parameters or a typed return value gets the same treatment as a boundary — with no checks written by you:
function processUser(user: User): UserResult {
return computeSomething(user)
}
becomes, at build time:
function processUser(user): UserResult {
user = check(user, /* schema for User */)
return check(computeSomething(user), /* schema for UserResult */)
}
A bad payload at the call site fails before computeSomething runs. A buggy
implementation that returns the wrong shape fails before the value leaves the
function.
Destructured parameters are skipped. A param written as
{ id, name }: Useris already destructured, so there’s no single binding to revalidate — t12n leaves it alone. Take the value whole (user: User) and destructure inside the body if you want the check, or mark itCheck<User>to be told it was skipped.
In a production build each of those checks is a compiled validator, not an interpreted schema — so the guarantee is effectively free.