Matcher Class
Signature
class Matcher<TSubject, TResult> {
constructor(subject: TSubject)
on(pattern: TSubject | Predicate<TSubject>, handler: () => TResult): this
onAny(values: readonly TSubject[], handler: () => TResult): this
otherwise(handler: () => TResult): TResult
default(handler: () => TResult): TResult
valueOf(): TResult
run(): boolean
get isMatched(): boolean
}Description
The Matcher class implements the match expression pattern with eager execution. Handlers execute immediately when a match is found. It supports both literal value matching and predicate functions.
Type Parameters
TSubject- The type of values being matchedTResult- The return type of handler functions
Constructor
new Matcher<TSubject, TResult>(subject: TSubject)Usually, you don't instantiate this directly. Use the match() function instead:
import { match } from '@anilkumarthakur/match'
const matcher = match(value) // Not new Matcher(value)Methods
on(pattern, handler): this
Adds a case to match against. Pattern can be a literal value or a predicate function.
matcher.on(pattern, handler)Parameters:
pattern: TSubject | Predicate<TSubject>- Literal value (matched withObject.is()) or predicate function(subject) => booleanhandler: () => TResult- Function to execute if matched
Returns: this for method chaining
Behavior:
- If pattern is a function AND subject is not a function → treat as predicate
- If pattern is a literal → use
Object.is()for comparison - If already matched, this call is ignored (first match wins)
- Handlers execute immediately upon match
Examples:
// Literal matching
match(200).on(200, () => 'Success')
// Predicate matching
match(10)
.on(
(n) => n > 5,
() => 'Greater than 5'
)
.on(
(n) => n <= 5,
() => 'Less than or equal to 5'
)
// Mixed
match(score)
.on(
(n) => n >= 90,
() => 'A'
)
.on(
(n) => n >= 80,
() => 'B'
)onAny(values, handler): this
Adds multiple literal values that all map to the same handler.
matcher.onAny(values, handler)Parameters:
values: readonly TSubject[]- Array of literal values to matchhandler: () => TResult- Function to execute if any value matches
Returns: this for method chaining
Note: onAny() uses Object.is() for each comparison, so NaN will match.
Example:
match(code)
.onAny([200, 201, 202], () => 'Success')
.onAny([400, 401, 403], () => 'Client Error')otherwise(handler): TResult
Sets the default handler and executes the match expression. Called if no matches found.
const result = matcher.otherwise(handler)Parameters:
handler: () => TResult- Function to execute if no cases match
Returns: TResult - The result from matched handler or default
Throws: Any error thrown by the handler
Example:
const result = match(value)
.on('case1', () => 'result1')
.otherwise(() => 'default')default(handler): TResult
PHP-compatible alias for otherwise(). Identical behavior.
const result = matcher.default(handler)Parameters:
handler: () => TResult- Function to execute if no cases match
Returns: TResult - The result from matched handler or default
Example:
const result = match(value)
.on('case1', () => 'result1')
.default(() => 'default')valueOf(): TResult
Executes the match without a default handler.
const result = matcher.valueOf()Returns: TResult - The result from the matched handler
Throws: UnhandledMatchError if no match found
Example:
try {
const result = match('test')
.on('test', () => 'matched')
.valueOf()
console.log(result)
} catch (error) {
console.error('No match:', error.message)
}run(): boolean
Execute for side effects only. Returns boolean indicating if a match occurred.
const didMatch = matcher.run()Returns: boolean - true if a match was found and handler executed, false otherwise
Example:
const handled = match(action)
.on('save', () => saveData())
.on('delete', () => deleteData())
.run()
if (!handled) {
console.warn('Unknown action')
}isMatched Property
Get current match state.
const matched = matcher.isMatchedReturns: boolean - true if a match has been found
Example:
const matcher = match('test').on('test', () => 'matched')
console.log(matcher.isMatched) // true
const matcher2 = match('other').on('test', () => 'matched')
console.log(matcher2.isMatched) // falseBehavior Notes
Eager Execution
Handlers execute immediately when matched, before returning from .on():
let value = 'initial'
match('test').on('test', () => {
value = 'changed'
})
// value is now 'changed'
console.log(value) // "changed"First Match Wins
Once a match is found, subsequent .on() calls are ignored:
let calls = 0
match('x')
.on('x', () => {
calls++
})
.on('x', () => {
calls++
}) // ignored
.otherwise(() => {})
console.log(calls) // 1Object.is() Semantics
Matching uses Object.is() instead of ===:
match(NaN).on(NaN, () => 'matched!') // Works!
match(+0)
.on(-0, () => 'nope')
.on(+0, () => 'matched!') // Works! Object.is(+0, -0) === falseComplete Example
import { match } from '@anilkumarthakur/match'
// Grade calculator with predicates
const grade = (score: number) =>
match(score)
.on(
(n) => n >= 90,
() => 'A'
)
.on(
(n) => n >= 80,
() => 'B'
)
.on(
(n) => n >= 70,
() => 'C'
)
.otherwise(() => 'F')
console.log(grade(95)) // "A"
console.log(grade(75)) // "C"
// Side-effect handler
let status = 'pending'
match('ready')
.on('ready', () => {
status = 'active'
})
.on('stop', () => {
status = 'stopped'
})
// status is now 'active'
console.log(status) // "active"Related
- match() Function - The recommended way to create matchers
- Predicate Type - Function predicate type
- UnhandledMatchError - Error thrown on no match