TypeScript `asserts` and Type Predicates in 2026: Writing Guards That Actually Narrow Correctly TypeScript developers often write validation guards that compile but fail to narrow types, leading to runtime bugs. The key is using type predicates (`value is Type`) for conditional narrowing and assertion functions (`asserts value is Type`) for unconditional narrowing, as explained in a new guide. The guide emphasizes that plain boolean returns provide no type information and demonstrates correct patterns for runtime data validation. asserts and Type Predicates in 2026: Writing Guards That Actually Narrow Correctly This article was written with the assistance of AI, under human supervision and review. Most TypeScript runtime validation breaks down because engineers write guards that compile but don't actually narrow types where it matters. The pattern that teams overlook is the distinction between type predicates that return boolean values and assertion functions that throw on failure—and choosing the wrong one creates silent bugs that surface in production. The problem starts when developers write a function like isUser value: unknown : boolean and expect TypeScript to understand what that boolean means. The compiler sees the function return true but has no idea that value is now safe to treat as a User type. Code that looks validated crashes at runtime because the type system never learned what the validation actually proved. The fix is adding the type predicate syntax value is User to the return signature. This tells TypeScript that when the function returns true , the narrowed type holds in the calling scope. For throwing guards that never return on failure, the asserts keyword encodes that guarantee into the signature itself. That distinction is critical. Type predicates return booleans and enable conditional narrowing. Assertion functions throw errors and narrow the remainder of the scope unconditionally. Mixing them up or using neither creates validation theater—code that runs checks but provides zero type safety. value is Type narrow types conditionally when the guard returns true , while assertion functions asserts value is Type narrow unconditionally by throwing on failure. boolean instead of using predicate syntax—the compiler cannot infer type information from a plain boolean. value is T work with utility types like NonNullable