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 }: User is 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 it Check<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.