Skip to content

Nested Matching

Advanced patterns using nested match expressions.

Basic Nested Matching

typescript
import { match } from '@anilkumarthakur/match'

const getUserAccess = (userType: string, status: string): string => {
  return match(userType)
    .on('admin', () => {
      return match(status)
        .on('active', () => 'Admin - Full Access')
        .on('suspended', () => 'Admin - Suspended')
        .otherwise(() => 'Admin - Limited')
    })
    .on('moderator', () => {
      return match(status)
        .on('active', () => 'Moderator - Can moderate')
        .on('suspended', () => 'Moderator - Banned')
        .otherwise(() => 'Moderator - Limited')
    })
    .on('user', () => {
      return match(status)
        .on('active', () => 'User - Can post')
        .on('banned', () => 'User - Banned')
        .otherwise(() => 'User - Limited')
    })
    .otherwise(() => 'Unknown Role')
}

console.log(getUserAccess('admin', 'active')) // "Admin - Full Access"
console.log(getUserAccess('user', 'banned')) // "User - Banned"
console.log(getUserAccess('unknown', 'active')) // "Unknown Role"

Transaction Status with Nested Logic

typescript
interface Transaction {
  type: 'payment' | 'refund' | 'transfer'
  status: 'pending' | 'completed' | 'failed'
}

const getTransactionInfo = (tx: Transaction): { action: string; message: string } => {
  return match(tx.type)
    .on('payment', () => {
      return match(tx.status)
        .on('pending', () => ({
          action: 'wait',
          message: 'Payment is being processed...'
        }))
        .on('completed', () => ({
          action: 'success',
          message: 'Payment completed successfully'
        }))
        .on('failed', () => ({
          action: 'retry',
          message: 'Payment failed - please try again'
        }))
        .otherwise(() => ({
          action: 'error',
          message: 'Unknown payment status'
        }))
    })
    .on('refund', () => {
      return match(tx.status)
        .on('pending', () => ({
          action: 'wait',
          message: 'Refund is being processed...'
        }))
        .on('completed', () => ({
          action: 'success',
          message: 'Refund completed'
        }))
        .on('failed', () => ({
          action: 'support',
          message: 'Refund failed - contact support'
        }))
        .otherwise(() => ({
          action: 'error',
          message: 'Unknown refund status'
        }))
    })
    .on('transfer', () => {
      return match(tx.status)
        .on('pending', () => ({
          action: 'wait',
          message: 'Transfer in progress...'
        }))
        .on('completed', () => ({
          action: 'success',
          message: 'Transfer completed'
        }))
        .on('failed', () => ({
          action: 'retry',
          message: 'Transfer failed - retry?'
        }))
        .otherwise(() => ({
          action: 'error',
          message: 'Unknown transfer status'
        }))
    })
    .otherwise(() => ({
      action: 'error',
      message: 'Unknown transaction type'
    }))
}

console.log(getTransactionInfo({ type: 'payment', status: 'completed' }))
// { action: 'success', message: 'Payment completed successfully' }

Multi-Level Nested Matching

typescript
interface Order {
  status: 'new' | 'processing' | 'shipped' | 'delivered'
  priority: 'urgent' | 'normal' | 'low'
  paymentMethod: 'card' | 'wallet' | 'cod'
}

const getOrderWorkflow = (order: Order): { nextStep: string; timeframe: string } => {
  return match(order.status)
    .on('new', () => {
      return match(order.priority)
        .on('urgent', () => ({
          nextStep: 'Process immediately',
          timeframe: '1 hour'
        }))
        .on('normal', () => ({
          nextStep: 'Add to queue',
          timeframe: '4 hours'
        }))
        .on('low', () => ({
          nextStep: 'Schedule for next batch',
          timeframe: '24 hours'
        }))
        .otherwise(() => ({
          nextStep: 'Verify',
          timeframe: 'Unknown'
        }))
    })
    .on('processing', () => {
      return match(order.paymentMethod)
        .on('card', () => ({
          nextStep: 'Verify card payment',
          timeframe: '15 minutes'
        }))
        .on('wallet', () => ({
          nextStep: 'Check wallet balance',
          timeframe: '5 minutes'
        }))
        .on('cod', () => ({
          nextStep: 'Prepare for shipment',
          timeframe: '1 hour'
        }))
        .otherwise(() => ({
          nextStep: 'Verify payment',
          timeframe: 'Unknown'
        }))
    })
    .on('shipped', () => ({
      nextStep: 'Track shipment',
      timeframe: 'In transit'
    }))
    .on('delivered', () => ({
      nextStep: 'Collect feedback',
      timeframe: 'Complete'
    }))
    .otherwise(() => ({
      nextStep: 'Unknown',
      timeframe: 'Unknown'
    }))
}

const order: Order = { status: 'processing', priority: 'normal', paymentMethod: 'card' }
console.log(getOrderWorkflow(order))
// { nextStep: 'Verify card payment', timeframe: '15 minutes' }

Nested Matching with Arrays

typescript
interface User {
  role: 'admin' | 'user'
  status: 'active' | 'inactive'
  permissions: string[]
}

const getPermissionActions = (user: User): string[] => {
  return match(user.role)
    .on('admin', () => {
      return match(user.status)
        .on('active', () => [
          'create_content',
          'edit_content',
          'delete_content',
          'manage_users',
          'view_analytics'
        ])
        .on('inactive', () => ['view_content', 'view_analytics'])
        .otherwise(() => [])
    })
    .on('user', () => {
      return match(user.status)
        .on('active', () => ['create_content', 'edit_own_content', 'delete_own_content'])
        .on('inactive', () => ['view_content'])
        .otherwise(() => [])
    })
    .otherwise(() => [])
}

const admin: User = { role: 'admin', status: 'active', permissions: [] }
console.log(getPermissionActions(admin))
// ['create_content', 'edit_content', 'delete_content', 'manage_users', 'view_analytics']

Nested Matching with Default Fallthrough

typescript
interface Document {
  type: 'report' | 'memo' | 'draft'
  visibility: 'public' | 'private' | 'shared'
}

const getAccessLevel = (doc: Document): number => {
  return match(doc.type)
    .on('report', () => {
      return match(doc.visibility)
        .on('public', () => 3)
        .on('shared', () => 2)
        .on('private', () => 1)
        .otherwise(() => 0)
    })
    .on('memo', () => {
      return match(doc.visibility)
        .on('public', () => 2)
        .on('shared', () => 1)
        .on('private', () => 0)
        .otherwise(() => -1)
    })
    .otherwise(() => {
      // Default for any other type
      return match(doc.visibility)
        .on('public', () => 1)
        .on('shared', () => 0)
        .on('private', () => -1)
        .otherwise(() => -1)
    })
}

console.log(getAccessLevel({ type: 'report', visibility: 'public' })) // 3
console.log(getAccessLevel({ type: 'memo', visibility: 'shared' })) // 1

Next Examples

Released under the MIT License.