Last Updated: 3/6/2026
Number and BigInt Predicates
P.number and P.bigint provide methods for matching numbers and bigints based on their values.
P.number.between()
Matches numbers between min and max (inclusive).
import { match, P } from 'ts-pattern';
const fn = (input: number) =>
match(input)
.with(P.number.between(1, 5), () => '✅ Between 1 and 5')
.otherwise(() => '❌ Outside range');
console.log(fn(3)); // ✅ Between 1 and 5
console.log(fn(1)); // ✅ Between 1 and 5 (inclusive)
console.log(fn(5)); // ✅ Between 1 and 5 (inclusive)
console.log(fn(7)); // ❌ Outside rangeP.number.lt()
Matches numbers less than the specified value.
const fn = (input: number) =>
match(input)
.with(P.number.lt(0), () => 'Negative')
.with(P.number.lt(10), () => 'Less than 10')
.otherwise(() => '10 or greater');
console.log(fn(-5)); // Negative
console.log(fn(5)); // Less than 10
console.log(fn(15)); // 10 or greaterP.number.gt()
Matches numbers greater than the specified value.
const fn = (input: number) =>
match(input)
.with(P.number.gt(100), () => 'Large number')
.with(P.number.gt(0), () => 'Positive')
.otherwise(() => 'Zero or negative');
console.log(fn(150)); // Large number
console.log(fn(50)); // Positive
console.log(fn(-10)); // Zero or negativeP.number.lte()
Matches numbers less than or equal to the specified value.
const fn = (input: number) =>
match(input)
.with(P.number.lte(0), () => 'Zero or negative')
.otherwise(() => 'Positive');
console.log(fn(0)); // Zero or negative
console.log(fn(-5)); // Zero or negative
console.log(fn(5)); // PositiveP.number.gte()
Matches numbers greater than or equal to the specified value.
const fn = (input: number) =>
match(input)
.with(P.number.gte(18), () => 'Adult')
.otherwise(() => 'Minor');
console.log(fn(18)); // Adult
console.log(fn(25)); // Adult
console.log(fn(15)); // MinorP.number.int()
Matches integer numbers (no decimal part).
const fn = (input: number) =>
match(input)
.with(P.number.int(), () => 'Integer')
.otherwise(() => 'Decimal');
console.log(fn(42)); // Integer
console.log(fn(-7)); // Integer
console.log(fn(3.14)); // DecimalP.number.finite()
Matches all finite numbers (excludes Infinity and -Infinity).
const fn = (input: number) =>
match(input)
.with(P.number.finite(), (n) => `Finite: ${n}`)
.otherwise(() => 'Infinite');
console.log(fn(42)); // Finite: 42
console.log(fn(Infinity)); // Infinite
console.log(fn(-Infinity)); // InfiniteP.number.positive()
Matches positive numbers (greater than 0).
const fn = (input: number) =>
match(input)
.with(P.number.positive(), () => 'Positive')
.otherwise(() => 'Zero or negative');
console.log(fn(5)); // Positive
console.log(fn(0)); // Zero or negative
console.log(fn(-5)); // Zero or negativeP.number.negative()
Matches negative numbers (less than 0).
const fn = (input: number) =>
match(input)
.with(P.number.negative(), () => 'Negative')
.otherwise(() => 'Zero or positive');
console.log(fn(-5)); // Negative
console.log(fn(0)); // Zero or positive
console.log(fn(5)); // Zero or positiveBigInt Predicates
All numeric predicates are also available for bigints:
match(value)
.with(P.bigint.between(0n, 100n), () => 'Small bigint')
.with(P.bigint.gt(100n), () => 'Large bigint')
.with(P.bigint.positive(), () => 'Positive bigint')
.otherwise(() => 'Other');Chaining Predicates
Numeric predicates can be chained:
match(age)
.with(
P.number.int().positive().gte(18).lte(65),
() => 'Working age adult'
)
.otherwise(() => 'Other');Combining with Other Patterns
With Objects
type Product = {
price: number;
stock: number;
};
match(product)
.with(
{
price: P.number.positive().lt(100),
stock: P.number.gt(0),
},
(p) => 'Affordable and in stock'
)
.with(
{ stock: P.number.lte(0) },
() => 'Out of stock'
)
.otherwise(() => 'Expensive');With P.select()
match(data)
.with(
{ score: P.number.between(90, 100).select() },
(score) => {
// score: number (between 90 and 100)
return `A grade: ${score}`;
}
)
.otherwise(() => 'Lower grade');With Arrays
match(temperatures)
.with(
P.array(P.number.between(20, 25)),
(temps) => 'All comfortable temperatures'
)
.otherwise(() => 'Mixed temperatures');Real-World Examples
Age Validation
type User = { age: number };
const validateAge = (user: User) =>
match(user)
.with(
{ age: P.number.int().gte(0).lte(120) },
() => ({ valid: true })
)
.otherwise(() => ({ valid: false, error: 'Invalid age' }));Price Range Filter
type PriceRange = 'budget' | 'mid' | 'premium';
const getPriceRange = (price: number): PriceRange =>
match(price)
.with(P.number.lt(50), () => 'budget' as const)
.with(P.number.between(50, 200), () => 'mid' as const)
.with(P.number.gt(200), () => 'premium' as const)
.exhaustive();HTTP Status Codes
const handleStatus = (code: number) =>
match(code)
.with(P.number.between(200, 299), () => 'Success')
.with(P.number.between(300, 399), () => 'Redirect')
.with(P.number.between(400, 499), () => 'Client Error')
.with(P.number.between(500, 599), () => 'Server Error')
.otherwise(() => 'Unknown');Temperature Conversion
type Temperature = { celsius: number };
const describeTemperature = (temp: Temperature) =>
match(temp)
.with(
{ celsius: P.number.lt(0) },
() => 'Freezing'
)
.with(
{ celsius: P.number.between(0, 15) },
() => 'Cold'
)
.with(
{ celsius: P.number.between(15, 25) },
() => 'Comfortable'
)
.with(
{ celsius: P.number.gt(25) },
() => 'Hot'
)
.exhaustive();Pagination
type PaginationParams = {
page: number;
pageSize: number;
};
const validatePagination = (params: PaginationParams) =>
match(params)
.with(
{
page: P.number.int().positive(),
pageSize: P.number.int().between(1, 100),
},
(p) => ({ valid: true, params: p })
)
.otherwise(() => ({ valid: false, error: 'Invalid pagination' }));Score Grading
const getGrade = (score: number) =>
match(score)
.with(P.number.between(90, 100), () => 'A')
.with(P.number.between(80, 89), () => 'B')
.with(P.number.between(70, 79), () => 'C')
.with(P.number.between(60, 69), () => 'D')
.with(P.number.lt(60), () => 'F')
.otherwise(() => 'Invalid score');Best Practices
-
Use specific predicates: More readable than generic
P.when()// Good P.number.between(1, 10) // Less clear P.when((n) => n >= 1 && n <= 10) -
Chain for complex conditions:
P.number.int().positive().lte(100) -
Combine with type narrowing:
.with({ age: P.number.gte(18) }, (user) => { // TypeScript knows user.age >= 18 }) -
Use with P.select() to extract validated values:
.with( { price: P.number.positive().select() }, (price) => `Valid price: $${price}` )