Functional Enum type / Sum type for javascript with simple pattern matching
Checkout the docs for more information
Medium article on SumTypes using EnumFP
yarn add enum-fp
import Enum from 'enum-fp';
const Action = Enum([ 'Add', 'Edit', 'Delete', 'Get' ]);
// Or with a fixed number of arguments
const Maybe = Enum({
Just: [ 'value' ],
Nothing: [],
});
const action = Action.Edit(2, 'Hello world and India');
const Action = Enum([ 'Add', 'Edit', 'Delete', 'DeleteAll', 'Get' ]);
const logMessage = action => console.log('>>',
Action.match(action, {
Edit: (id, message) => `Editing [${id}] to "${message}"`,
Add: message => `Adding "${message}"`,
Delete: id => `Deleting [${id}]`,
DeleteAll: () => 'Deleting all entries',
_: () => 'Unknown action', // To handle default cases, use _
})
);
logMessage(Action.Add('Earth')); // >> Adding "Earth"
logMessage(Action.Add('Earth 2')); // >> Adding "Earth 2"
logMessage(Action.Add('Pluto'));
logMessage(Action.Add('Pluto')); // >> Adding "Pluto1"
logMessage(Action.Edit(1, 'Mars')); // >> Editing [2] to "Mars"
logMessage(Action.Delete(2)); // >> Deleting [3]
logMessage(Action.Add('Pluto')); // >> Adding "Pluto"
logMessage(Action.DeleteAll()); // >> Deleting all entries
// As Get action is not handled in the pattern, it will execute the default
logMessage(Action.Get()); // >> Unknown action
You can add strict type validation instead of argument descriptions. You can read more about types module here
import T from 'enum-fp/types';
const TodoAction = Enum({
Add: [ T.String('message') ],
SetChecked: [ T.Number('id'), T.Bool('isChecked') ],
Delete: [ T.Number('id') ],
Edit: [ T.Number('id'), T.String('message') ],
DeleteAll: [],
});
NOTE: The string passed to the functions are just for documentation purposes and are optional. It won't affect the behavior of the type in any way.
You can use it to manage react component state!
Checkout the documentation
- Working with invalid values
// Just an example. You should use `Maybe` functor in cases like these
const Value = Enum({ Invalid: [], Valid: ['value'] });
const extractName = user => user && user.name
? Value.Valid(user.name)
: Value.Invalid();
const splitBySpace = Value.cata({
Valid: name => name.split(' '),
Invalid: () => [],
});
const getNameSplit = compose(splitBySpace, extractName);
const [ firstName, lastName ] = getNameSplit({ name: 'Akshay Nair' }); // >> returns ['Akshay','Nair']
If you are unfamiliar with functors
, you can read Functors in JS blog post.
- Maybe
Maybe
functor is used to handle null.
const Maybe = Enum({ Just: ['value'], Nothing: [] });
const fmap = fn => Maybe.cata({
Just: compose(Maybe.Just, fn),
Nothing: Maybe.Nothing,
});
- Either
Either
functor is used for handling exceptions
const Either = Enum({ Left: ['error'], Right: ['value'] });
const fmap = fn => Either.cata({
Left: Either.Left,
Right: compose(Either.Right, fn),
});
const fmapFail = fn => Either.cata({
Left: compose(Either.Left, fn),
Right: Either.Right,
});