TypeScript Predicate Type Guards
Narrow union types with custom type predicates for safer, more expressive code
Introduction
Type predicates are a powerful TypeScript feature that lets you create custom type guards. They enable you to narrow union types based on runtime checks, providing type safety throughout your codebase.
What is a Type Predicate?
A type predicate is a function whose return type is a special kind of type assertion: parameterName is Type.
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
The pet is Fish is our type predicate. It tells TypeScript: "If this function returns true, then pet is definitely a Fish."
How Type Predicates Work
When you use a type predicate in a conditional, TypeScript narrows the type within that block.
let pet = getSmallPet();
if (isFish(pet)) {
pet.swim(); // TypeScript knows pet is Fish
} else {
pet.fly(); // TypeScript knows pet is Bird
}
Practical Examples
Property Checks
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
Type Narrowing with typeof
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function process(value: string | number) {
if (isString(value)) {
return value.toUpperCase();
}
return value.toFixed(2);
}
Array Filtering
function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
const values: (string | null | undefined)[] = ['hello', null, 'world'];
const filtered = values.filter(isDefined); // Type: string[]
Best Practices
- Always perform actual runtime checks
- Use
unknownfor input parameters - Keep predicates simple and focused
- Document complex predicates
Conclusion
Type predicates bridge compile-time types and runtime checks, enabling safer TypeScript code.
#typescript #types #type-safety