InlineSwitch: A Flexible Pattern Matching Library for TypeScript

Introduction In modern JavaScript and TypeScript applications, we often need to handle complex conditional logic. Traditional switch statements and if-else chains quickly become unwieldy as complexity grows. That's why I'm excited to introduce InlineSwitch, a tiny yet powerful library that brings pattern matching to JavaScript and TypeScript. The Problem with Traditional Approaches Before we dive into InlineSwitch, let's examine the shortcomings of traditional conditional approaches: Switch Statements switch (value) { case 1: return 'One'; case 2: return 'Two'; case 3: return 'Three'; default: return 'Unknown'; } Switch statements are limited to simple equality checks and require break statements to avoid fall-through issues. They also don't support complex conditions like ranges or custom logic. If-Else Chains if (value === 1) { return 'One'; } else if (value === 2) { return 'Two'; } else if (value === 3) { return 'Three'; } else { return 'Unknown'; } If-else chains are verbose and become hard to read as they grow longer. They're also difficult to maintain when adding or removing conditions. Enter InlineSwitch InlineSwitch is a lightweight pattern matching library that provides a clean, functional approach to conditional logic. It supports: Exact value matching Array membership testing Predicate function testing Default case handling All with concise, readable syntax and full TypeScript support. Installation npm install inlineswitch Basic Usage Here's a simple example of InlineSwitch in action: import { inlineSwitch } from 'inlineswitch'; function getDiscount(userType: string) { return inlineSwitch( userType, [ ['premium', () => 0.2], // 20% discount for premium users ['regular', () => 0.1], // 10% discount for regular users ['new', () => 0.15], // 15% discount for new users ], () => 0.05 // 5% default discount ); } Advanced Pattern Matching InlineSwitch really shines with more complex patterns: Array Matching const fruitCategory = inlineSwitch( 'apple', [ [['apple', 'pear'], () => 'pome'], [['peach', 'plum', 'cherry'], () => 'drupe'], [['grape', 'blueberry'], () => 'berry'], ], () => 'other' ); // Result: 'pome' Predicate Functions const sizeCategory = inlineSwitch( 42, [ [(n) => n 'small'], [(n) => n >= 10 && n 'medium'], [(n) => n >= 100, () => 'large'], ] ); // Result: 'medium' Using the Value Each handler receives the original value, allowing for more dynamic results: const result = inlineSwitch( 15, [ [(n) => n % 3 === 0, (n) => `${n} is divisible by 3`], [(n) => n % 5 === 0, (n) => `${n} is divisible by 5`], [(n) => n % 3 === 0 && n % 5 === 0, (n) => `${n} is divisible by both 3 and 5`], ], (n) => `${n} is not divisible by 3 or 5` ); // Result: '15 is divisible by 5' Type Safety InlineSwitch is fully typed, providing excellent IntelliSense support and catching type errors at compile time: type User = { id: number; type: 'admin' | 'editor' | 'viewer'; }; const permissions = inlineSwitch( user, [ [(u) => u.type === 'admin', () => ['read', 'write', 'delete', 'admin']], [(u) => u.type === 'editor', () => ['read', 'write']], [(u) => u.type === 'viewer', () => ['read']], ] ); Error Prevention InlineSwitch checks for duplicate case values at runtime: // This will throw a DuplicateCaseError inlineSwitch( value, [ [1, () => 'One'], [1, () => 'Also One'], // Duplicate key! ] ); Shorthand Syntax For simple use cases, InlineSwitch provides a more concise API: import { switchValue } from 'inlineswitch'; const color = switchValue( 'red', ['red', () => '#ff0000'], ['green', () => '#00ff00'], ['blue', () => '#0000ff'] ); // Result: '#ff0000' Real-World Examples HTTP Status Code Handling const message = inlineSwitch( statusCode, [ [[200, 201, 204], () => 'Success'], [[400, 401, 403, 404], () => 'Client Error'], [[500, 502, 503, 504], () => 'Server Error'], ], () => 'Unknown Status' ); User Roles and Permissions const userInterface = inlineSwitch( userRole, [ ['admin', () => ], ['manager', () => ], ['employee', () => ], ['guest', () => ], ], () => ); Form Validation const validationError = inlineSwitch( password.length, [ [(len) => len 'Password is too short'], [(len) => len > 64, () => 'Password is too long'], [(len) => len >= 8 && len null], ] ); Performance Considerations InlineSwitch is designed for readability and flexibility rather than raw performance. For simple equality checks where performance is critical, native switch statements mi

Apr 24, 2025 - 16:48
 0
InlineSwitch: A Flexible Pattern Matching Library for TypeScript

Introduction

In modern JavaScript and TypeScript applications, we often need to handle complex conditional logic. Traditional switch statements and if-else chains quickly become unwieldy as complexity grows. That's why I'm excited to introduce InlineSwitch, a tiny yet powerful library that brings pattern matching to JavaScript and TypeScript.

The Problem with Traditional Approaches

Before we dive into InlineSwitch, let's examine the shortcomings of traditional conditional approaches:

Switch Statements

switch (value) {
  case 1:
    return 'One';
  case 2:
    return 'Two';
  case 3:
    return 'Three';
  default:
    return 'Unknown';
}

Switch statements are limited to simple equality checks and require break statements to avoid fall-through issues. They also don't support complex conditions like ranges or custom logic.

If-Else Chains

if (value === 1) {
  return 'One';
} else if (value === 2) {
  return 'Two';
} else if (value === 3) {
  return 'Three';
} else {
  return 'Unknown';
}

If-else chains are verbose and become hard to read as they grow longer. They're also difficult to maintain when adding or removing conditions.

Enter InlineSwitch

InlineSwitch is a lightweight pattern matching library that provides a clean, functional approach to conditional logic. It supports:

  1. Exact value matching
  2. Array membership testing
  3. Predicate function testing
  4. Default case handling

All with concise, readable syntax and full TypeScript support.

Installation

npm install inlineswitch

Basic Usage

Here's a simple example of InlineSwitch in action:

import { inlineSwitch } from 'inlineswitch';

function getDiscount(userType: string) {
  return inlineSwitch(
    userType,
    [
      ['premium', () => 0.2],  // 20% discount for premium users
      ['regular', () => 0.1],  // 10% discount for regular users
      ['new', () => 0.15],     // 15% discount for new users
    ],
    () => 0.05  // 5% default discount
  );
}

Advanced Pattern Matching

InlineSwitch really shines with more complex patterns:

Array Matching

const fruitCategory = inlineSwitch(
  'apple',
  [
    [['apple', 'pear'], () => 'pome'],
    [['peach', 'plum', 'cherry'], () => 'drupe'],
    [['grape', 'blueberry'], () => 'berry'],
  ],
  () => 'other'
);
// Result: 'pome'

Predicate Functions

const sizeCategory = inlineSwitch(
  42,
  [
    [(n) => n < 10, () => 'small'],
    [(n) => n >= 10 && n < 100, () => 'medium'],
    [(n) => n >= 100, () => 'large'],
  ]
);
// Result: 'medium'

Using the Value

Each handler receives the original value, allowing for more dynamic results:

const result = inlineSwitch(
  15,
  [
    [(n) => n % 3 === 0, (n) => `${n} is divisible by 3`],
    [(n) => n % 5 === 0, (n) => `${n} is divisible by 5`],
    [(n) => n % 3 === 0 && n % 5 === 0, (n) => `${n} is divisible by both 3 and 5`],
  ],
  (n) => `${n} is not divisible by 3 or 5`
);
// Result: '15 is divisible by 5'

Type Safety

InlineSwitch is fully typed, providing excellent IntelliSense support and catching type errors at compile time:

type User = {
  id: number;
  type: 'admin' | 'editor' | 'viewer';
};

const permissions = inlineSwitch<User, string[]>(
  user,
  [
    [(u) => u.type === 'admin', () => ['read', 'write', 'delete', 'admin']],
    [(u) => u.type === 'editor', () => ['read', 'write']],
    [(u) => u.type === 'viewer', () => ['read']],
  ]
);

Error Prevention

InlineSwitch checks for duplicate case values at runtime:

// This will throw a DuplicateCaseError
inlineSwitch(
  value,
  [
    [1, () => 'One'],
    [1, () => 'Also One'], // Duplicate key!
  ]
);

Shorthand Syntax

For simple use cases, InlineSwitch provides a more concise API:

import { switchValue } from 'inlineswitch';

const color = switchValue(
  'red',
  ['red', () => '#ff0000'],
  ['green', () => '#00ff00'],
  ['blue', () => '#0000ff']
);
// Result: '#ff0000'

Real-World Examples

HTTP Status Code Handling

const message = inlineSwitch(
  statusCode,
  [
    [[200, 201, 204], () => 'Success'],
    [[400, 401, 403, 404], () => 'Client Error'],
    [[500, 502, 503, 504], () => 'Server Error'],
  ],
  () => 'Unknown Status'
);

User Roles and Permissions

const userInterface = inlineSwitch(
  userRole,
  [
    ['admin', () => <AdminDashboard />],
    ['manager', () => <ManagerView />],
    ['employee', () => <EmployeePortal />],
    ['guest', () => <GuestView />],
  ],
  () => <UnauthorizedView />
);

Form Validation

const validationError = inlineSwitch(
  password.length,
  [
    [(len) => len < 8, () => 'Password is too short'],
    [(len) => len > 64, () => 'Password is too long'],
    [(len) => len >= 8 && len <= 64, () => null],
  ]
);

Performance Considerations

InlineSwitch is designed for readability and flexibility rather than raw performance. For simple equality checks where performance is critical, native switch statements might be faster. However, for complex conditional logic, InlineSwitch provides a much cleaner alternative with minimal overhead.

Under the Hood

InlineSwitch uses TypeScript's generic types and type guards to maintain type safety throughout the matching process. Here's a simplified look at the implementation:

function inlineSwitch<T, R>(
  value: T,
  cases: Array<[Pattern<T>, Handler<T, R>]>,
  defaultHandler?: Handler<T, R>
): R | undefined {
  const matchedCase = cases.find(([pattern]) => {
    if (Array.isArray(pattern)) {
      return pattern.includes(value);
    } else if (typeof pattern === 'function') {
      return pattern(value);
    } else {
      return pattern === value;
    }
  });

  return matchedCase ? matchedCase[1](value) : defaultHandler?.(value);
}

Conclusion

InlineSwitch brings pattern matching to JavaScript and TypeScript in a lightweight, type-safe package. By allowing you to express complex conditional logic clearly and concisely, it helps make your code more maintainable and easier to reason about.

For simple equality checks, it's as readable as a switch statement, but when you need more complex matching patterns, it scales elegantly where traditional approaches become unwieldy.

Give it a try in your next project, and enjoy the benefits of functional pattern matching in your JavaScript and TypeScript code!

npm install inlineswitch

Resources

Happy coding!