Simple Case Pattern Matching In Pure ES2015

While JavaScript does not have full pattern matching faculties, we can leverage ES2105 to implement the most basic and useful form.

What is a Case?

A case is simply just a bucket of data with a label. Cases are like pure data class or an object with a type field.

Here are some cases for different forms of communication.

Email(to, subject, body)
Sms(phone, body)
Letter(address, body)

Case Pattern Matching

Let’s say we have a stream of messages of all different cases and we want to send them off. But each case requires different processing. We use pattern matching to handle each case separately.

function send([case, ...parameters]) {
return {
Email(to, subject, body) {
return ses.sendEmail(createSesEmail(to, subject, body));
},

Sms(phone, body) {
return twilio.create(createTwilioMessage(phone, body));
},

Letter(address, body) {
return printEnvelope(address)
.then(() => printLetter(body))
.then(() => insertLetterIntoEnvelope())
.then(() => mailLetter());
}
}[case](...parameters);
}

To use this function, we need to format our cases as arrays.

send(['Email', 'jeph.kappa@blizz.com', 'McCree needs a buff', 'I think it is totally unfair Genji can kill McCree. Plx fix.']);
send(['Sms', '17762323', 'give me +1 strength']);
send(['Letter', 'Eon 18390 NE 68th St', 'Dear Mr. Must, Your Uber has arrived.']);

How It Works

Let’s rewrite the send function to be more verbose to show what is going on.

function send(message) {
function emailHandler(to, subject, body) {
return ses.sendEmail(createSesEmail(to, subject, body));
}
  function smsHandler(phone, body){
return twilio.create(createTwilioMessage(phone, body));
}
  function letterHandler(address, body) {
return printEnvelope(address)
.then(() => printLetter(body))
.then(() => insertLetterIntoEnvelope())
.then(() => mailLetter());
}
  const handlerByCase = {
Email: emailHandler,
Sms: smsHandler,
Letter: letterHandler
};
  const [case, ...parameters] = message;
const handler = handlerByCase[case];
return handler(...parameters);
}

Everything is fairly vanilla except for the destructuring and spread operator. We first use it to extract the case and parameters out of message. Parameters is an array. After we get the right handler using the case, we spread the parameters array as arguments into the handler. The handlers are inlined into handlerByCase object using method definitions.

Alternative Case Object Form

We can also use this pattern for case objects instead of arrays.

function send(message) {
return {
Email({to, subject, body}) {
return ses.sendEmail(createSesEmail(to, subject, body));
},

Sms({phone, body}) {
return twilio.create(createTwilioMessage(phone, body));
},

Letter({address, body}) {
return printEnvelope(address)
.then(() => printLetter(body))
.then(() => insertLetterIntoEnvelope())
.then(() => mailLetter());
}
}[message.case](message);
}

Calling this function would use objects.

send({
case: 'Email',
to: 'jeph.kappa@blizz.com',
subject: 'McCree needs a buff',
body: 'I think it is totally unfair Genji can kill McCree. Plx fix.'
});
send({
case: 'Sms',
phone: '17762323',
body: 'give me +1 strength'
});
send({
case: 'Letter',
address: 'Eon 18390 NE 68th St',
body: 'Dear Mr. Must, Your Uber has arrived.'
});

The case object form will become simpler once object rest is added to JavaScript

While we wait for full pattern matching to come to JavaScript, we can use this basic form of case pattern matching. If you have any questions or comments, please feel free to tweet me @pyrolistical