match
Namespace of composable argument matchers. Usable everywhere a value can appear: setup.when, expect.*.withArg, withArgs, matchExactly, withReturn, threw, and nested inside objects/arrays at any depth.
import { match, type Matcher, MATCHER_BRAND, isMatcher } from 'deride'Overview
A matcher is a brand-tagged object:
interface Matcher<T = unknown> {
readonly [MATCHER_BRAND]: true
readonly description: string
test(value: T): boolean
}The brand (Symbol.for('deride.matcher')) is globally registered — matchers from different deride versions installed side-by-side in the same tree still recognise each other.
Type matchers
match.any // Matcher<unknown> — accepts everything
match.defined // Matcher<unknown> — rejects only undefined
match.nullish // Matcher<unknown> — only null and undefined
match.string // Matcher<unknown> — typeof === 'string'
match.number // Matcher<unknown> — typeof === 'number' (NaN passes)
match.boolean // Matcher<unknown> — typeof === 'boolean'
match.bigint // Matcher<unknown> — typeof === 'bigint'
match.symbol // Matcher<unknown> — typeof === 'symbol'
match.function // Matcher<unknown> — typeof === 'function'
match.array // Matcher<unknown> — Array.isArray
match.object // Matcher<unknown> — non-null non-array objectStructural matchers
match.instanceOf(Ctor)
match.instanceOf<C>(ctor: C): Matcher<unknown>Passes when value instanceof Ctor. Subclasses match too.
match.objectContaining(partial)
match.objectContaining<T extends object>(partial: T): Matcher<unknown>Partial deep match — the value must contain every key from partial with a matching value. Extra keys allowed. Nested matchers work.
match.objectContaining({ id: match.number, name: match.string })match.arrayContaining(items)
match.arrayContaining<T>(items: T[]): Matcher<unknown>Every item in items must appear somewhere in the candidate array. Nested matchers work.
match.exact(value)
match.exact<T>(value: T): Matcher<unknown>Strict deep equal — extra keys or different types cause failure.
Comparators
match.gt <N extends number | bigint>(n: N): Matcher<number | bigint>
match.gte<N extends number | bigint>(n: N): Matcher<number | bigint>
match.lt <N extends number | bigint>(n: N): Matcher<number | bigint>
match.lte<N extends number | bigint>(n: N): Matcher<number | bigint>
match.between<N extends number | bigint>(low: N, high: N): Matcher<number | bigint>Mixed number/bigint comparisons reject. NaN never passes.
String matchers
match.regex(pattern: RegExp): Matcher<string> // resets lastIndex for /g and /y
match.startsWith(prefix: string): Matcher<string>
match.endsWith(suffix: string): Matcher<string>
match.includes(needle: string): Matcher<string>All reject non-string inputs — no coercion.
Logic combinators
match.not(m)
match.not<T>(m: Matcher<T>): Matcher<unknown>match.allOf(...matchers)
match.allOf(...matchers: Matcher<unknown>[]): Matcher<unknown>Every matcher must pass. Empty list is vacuously true — be careful with spread patterns.
match.oneOf(...matchers)
match.oneOf(...matchers: Matcher<unknown>[]): Matcher<unknown>At least one matcher must pass. Empty list is vacuously false.
match.anyOf(...values)
match.anyOf(...values: unknown[]): Matcher<unknown>Equality OR matcher-match against each listed value.
Escape hatch
match.where(predicate, description?)
match.where<T>(predicate: (value: T) => boolean, description?: string): Matcher<T>For one-off predicates. A thrown predicate is caught and treated as a non-match. Optional description appears in failure messages.
Shape utilities
isMatcher(value)
isMatcher(value: unknown): value is MatcherType guard. Useful if you're writing custom helpers that should recognise matchers the same way deride does.
MATCHER_BRAND
const MATCHER_BRAND: unique symbolThe global symbol brand. Hand-written matchers can set [MATCHER_BRAND]: true to integrate with deride's matcher-aware comparisons:
import { MATCHER_BRAND, type Matcher } from 'deride'
const isUUID: Matcher = {
[MATCHER_BRAND]: true,
description: 'UUID v4',
test: (v) => typeof v === 'string' && /^[0-9a-f-]{36}$/.test(v),
}See also
- Matchers guide — detailed examples and composition patterns