Advanced TypeScript

Type Guards & Assertion Functions

Type guards and assertion functions connect runtime checks to TypeScript's control-flow narrowing. They let the compiler understand that an unknown value has been validated.
  • A type guard returns a type predicate
  • An assertion function narrows or throws
  • The runtime check must be real
  • Guards are boundary tools
  • Schema libraries formalize this pattern
Type guard
type User = { id: string; name: string }

function isUser(value: unknown): value is User {
  return typeof value === "object" && value !== null
    && typeof (value as { id?: unknown }).id === "string"
    && typeof (value as { name?: unknown }).name === "string"
}

const data: unknown = await response.json()
if (isUser(data)) {
  console.log(data.name)
}
The guard performs runtime checks and teaches TypeScript about the result.
Assertion function
function assertUser(value: unknown): asserts value is User {
  if (!isUser(value)) {
    throw new Error("Invalid User")
  }
}

const raw: unknown = await response.json()
assertUser(raw)
raw.name // User
Assertions are useful when invalid input should abort the current path.
Sources
  • The TypeScript HandbookNarrowing
  • Effective TypeScript, 2nd EditionType guards
  • TypeScript ReferenceAssertion functions