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');
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')); // >> Adding "Pluto"
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 getName = user => user && user.name
? Value.Valid(user.name)
: Value.Invalid();
const splitBySpace = Value.cata({
Valid: name => name.split(' '),
Invalid: () => [],
});
const [ firstName, lastName ] = compose(splitBySpace, getName, getUser)();
- Maybe
const Maybe = Enum({ Just: ['value'], Nothing: [] });
const fmap = fn => Maybe.cata({
Just: compose(Maybe.Just, fn),
Nothing: Maybe.Nothing,
});
- Either
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,
});