Skip to Content
Number Predicates

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 range

P.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 greater

P.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 negative

P.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)); // Positive

P.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)); // Minor

P.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)); // Decimal

P.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)); // Infinite

P.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 negative

P.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 positive

BigInt 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

  1. Use specific predicates: More readable than generic P.when()

    // Good P.number.between(1, 10) // Less clear P.when((n) => n >= 1 && n <= 10)
  2. Chain for complex conditions:

    P.number.int().positive().lte(100)
  3. Combine with type narrowing:

    .with({ age: P.number.gte(18) }, (user) => { // TypeScript knows user.age >= 18 })
  4. Use with P.select() to extract validated values:

    .with( { price: P.number.positive().select() }, (price) => `Valid price: $${price}` )