A lightweight, flexible and powerful pattern matching library for JavaScript/TypeScript.
npm i @clctv/matchimport { match, Some, None, any, not, regex, when } from "@clctv/match";
const greeting = "hello";
const result = match(greeting, {
hello: () => "Exact match! ๐ฏ",
[when((v) => typeof v === "string")]: () => "Custom predicate match! ๐ฏ",
[when(greeting.length > 3)]: () => "Boolean condition met! ๐ข",
[any("hi", "hey")]: () => "Multiple values match! ๐ข",
[not("bye", "goodbye")]: () => 'Not "bye" or "goodbye" ๐ซ',
[regex("^h.*o$")]: () => "Regular expression match! ๐",
"h*o": () => "Wildcard match! โจ",
[Some]: () => "Has some value! โ
",
[None]: () => "Has no value! โ",
_: () => "Default case ๐คทโโ๏ธ",
});
console.log(result);- โ Some/None Matching: Check for presence or absence of a value
- ๐ฏ Exact Value Matching: Match exact string, number, boolean values
- ๐ฏ Custom Predicate Matching: Match using custom predicate functions or boolean values
- ๐ข Multiple Value Matching: Match against multiple possible values
- ๐ซ Negation Matching: Match when value is NOT one of specified values
- ๐ Regular Expression Matching: Match using regex patterns
- โจ Wildcard Matching: Simple wildcard patterns with
*and? - ๐ค Case Sensitivity Control: Configure case sensitivity of string matching
Main pattern matching function that evaluates a value against multiple patterns and returns the result of the matching pattern handler.
Parameters:
value: The value to match (string, number, boolean, null, undefined)patterns: Object mapping patterns to handler functionsoptions: Optional configurationcaseSensitive: Boolean (default: true)
Returns:
- The result of the first matching pattern handler
Conditionally execute a handler if the value matches the pattern.
Parameters:
value: The value to matchpattern: The pattern to match againsthandler: Function to execute if match is successful
Returns:
- Result of handler if matched, otherwise undefined
Check if a value matches a pattern without executing a handler.
Parameters:
value: The value to matchpattern: The pattern to match againstoptions: Optional configurationcaseSensitive: Boolean (default: true)
Returns:
- Boolean indicating whether the value matches the pattern
Create a custom predicate pattern.
- If a function is provided, the handler will be matched only if the function returns
truefor the input value. This is useful for advanced or flexible matching logic based on the value itself. - If a boolean is provided, the handler will be matched if the boolean is
true. This is useful for incorporating pre-calculated conditions or simple boolean flags into the matching logic.
// Using a predicate function
match(value, {
[when((v) => typeof v === "string" && v.length > 5)]: () => {
console.log("String longer than 5 characters!");
},
});
// Using a boolean value
match(value, {
[when(typeof value === "string" && value.length > 5)]: () => {
console.log("String longer than 5 characters!");
},
});Create a pattern that matches if the value equals any of the provided values.
match(value, {
[any("apple", "banana", "cherry")]: () => "This is a fruit!",
});Create a pattern that matches if the value does NOT equal any of the provided values.
match(value, {
[not("red", "blue", "green")]: () => "This is not a primary color!",
});Create a pattern that matches if the value matches the given regular expression.
match(value, {
[regex("^[0-9]+$")]: () => "This is a number!",
[regex("^[A-Z]+$", "i")]: () => "This contains only letters!",
});Matches any value that is not null or undefined.
match(value, {
[Some]: () => "Value exists!",
});Matches null or undefined values.
match(value, {
[None]: () => "No value provided!",
});Default case that matches if no other pattern matches.
match(value, {
// other patterns...
_: () => "Default fallback",
});// String matching
const fruit = "apple";
const fruitResult = match(fruit, {
apple: () => "๐ This is an apple",
banana: () => "๐ This is a banana",
orange: () => "๐ This is an orange",
_: () => "โ Unknown fruit",
});
// Number matching
const score = 85;
const grade = match(score, {
[any(90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)]: () => "A ๐",
[any(80, 81, 82, 83, 84, 85, 86, 87, 88, 89)]: () => "B ๐",
[any(70, 71, 72, 73, 74, 75, 76, 77, 78, 79)]: () => "C ๐",
[any(60, 61, 62, 63, 64, 65, 66, 67, 68, 69)]: () => "D ๐",
_: () => "F ๐ข",
});const input = "hello123";
const result = match(input, {
[regex("^[a-z]+$")]: () => "Only letters",
[regex("^[0-9]+$")]: () => "Only numbers",
[regex("^[a-z]+[0-9]+$")]: () => "Letters followed by numbers",
"hello*": () => "Starts with hello",
_: () => "No pattern matched",
});
// Result: 'Letters followed by numbers'const isAuthenticated = true;
const userRole = "editor";
const permission = match(userRole, {
[when(isAuthenticated && userRole === "admin")]: () => "Full Access",
[when(isAuthenticated && userRole === "editor")]: () => "Can Edit Content",
[when(isAuthenticated)]: () => "Logged In, Basic Access",
_: () => "Guest Access",
});
// Result: 'Can Edit Content'const command = "HELP";
const result = match(
command,
{
help: () => "Displaying help information",
exit: () => "Exiting the program",
version: () => "Current version: 1.0.0",
_: () => "Unknown command",
},
{ caseSensitive: false },
);
// Result: 'Displaying help information' (despite case difference)const username = getUserInput(); // Could be a string or undefined
const welcomeMessage =
ifLet(username, Some, () => {
return `Welcome back, ${username}!`;
}) || "Welcome, guest!";const data = fetchData(); // Could return null if fetch failed
const displayResult = match(data, {
[Some]: () => `Data loaded: ${processData(data)}`,
[None]: () => "Failed to load data. Please try again.",
});When multiple patterns could match a value, the following priority rules apply:
SomeandNonespecial patterns take highest priority- Exact matches (string/number/boolean)
whenpredicate patterns (both function and boolean variants)anyandnotcomposite value patterns- Regular expression patterns (
regex) - Wildcard patterns (
*,?, with fewer wildcards having higher priority) - Default case (
_) has the lowest priority
If no pattern matches and no default case (_) is provided, an error will be thrown:
// This will throw an error if value doesn't match any pattern
const result = match(value, {
pattern1: () => "Result 1",
pattern2: () => "Result 2",
// No default case!
});Pattern matching is particularly useful for:
- ๐ณ Handling complex conditional logic more elegantly than if/else chains
- ๐ฎ Processing user input and commands
- ๐ง Implementing state machines
- ๐ Transforming data based on various conditions
- โ๏ธ Processing configuration options
MIT