About
An expression-oriented fluent alternative to javascript's switch-statement that compiles away to ternary expressions.
Example
Source:
import Switch from 'switch-expr.macro';
const isAllowed = Switch(userType)
.case('employee', true)
.else('customer', false)
.default(false)();
Compiled output:
const isAllowed =
userType === 'employee' ? true : userType === 'customer' ? false : false;
Why ?
- Javascript switch-else statements are not expressions.
- Ternary expressions are ugly and even more so when nested.
- Solutions like lodash.cond have unnecessary function invocation overhead and are less readable. To ensure lazy evaluation we need to wrap each branch in function.
- We love fluent APIs.
This plugin is likely to become obsolete once do-expressions become supported by typescript (Relevant issue). If you don't care about type checking, then you can try out this babel-plugin.
Installation
This utility is implemented as a babel-macro.
Refer babel's setup instructions to learn how to setup your project to use babel for compilation.
- Install
babel-plugin-macros
andswitch-expr.macro
:
npm install --save-dev babel-plugin-macros switch-expr.macro
- Add babel-plugin-macros to .babelrc (if not already preset):
// .babelrc
module.exports = {
presets: [
// ... other presets
],
plugins: [
'babel-plugin-macros', // <-- REQUIRED
// ... other plugins
],
};
Features
- Branches are evaluated lazily
// src/foo.js
import Switch from 'switch-expr.macro';
const isAllowed = Switch(userType)
.case("employee", isEmployeeAllowed())
.else("customer", isCustomerAllowed())
.default(false)();
// if userType is "employee" then isCustomerAllowed function will never be
// executed
Usage with TypeScript
This library is type-safe and comes with type definitions.
All code must be processed through babel. Compilation through tsc (only) is not supported.
Recommended babel configuration:
// .babelrc
module.exports = {
presets: [
'@babel/preset-typescript',
// ... other presets
],
plugins: [
'babel-plugin-macros',
// ... other plugins
],
};
Flow based type inference
One caveat is that TypeScript's flow-based type inference will not treat .case
, .default
branches same as normal case/default
branches.
AFAIK, currently there is no workaround for feasible.
Caveats
Every Switch/case/default chain fluent must end with an terminating invocation without interruptions.
For example:
const a = 10;
const intermediate = Switch(a).case(1, 2);
const result = intermediate();
Above code will fail to compile.
Because the entire Switch/case/end chain is compiled away, anything returned by Switch/case/default can not be assigned, referenced, or used in any computation.
You may also like:
- if-expr.macro: Similar utility, providing a fluent expression-oriented macro replacement for if statement
License
MIT