match-by
v0.7.3
Published
Somewhere between pattern matching and a ternary
Downloads
14
Readme
This module was made with affection for but in no way trying to be a pattern matcher. We've already got that on the way. Instead, it is made to replace ugly ternary. It matches a test value to a simple key value. Simple in that the key must be a valid key in an object, so a primitive.
Motivating Examples
const traficLightDisplay =
intersection === 'stop'
? 'red'
: intersection === 'yeild'
? 'yellow'
: intersection === 'go'
? 'green'
: 'yellow flashing';
becomes
const lightOptions = {
stop: 'red',
yeild: 'yellow',
go: 'green',
_: 'yellow flashing'
};
const traficLightDisplay = match( lightOptions, 'stop' );
Though that situation could be cleared up with a mapper function. What a mapper couldn't cleanly handle for you would be something like
const ViewType = user.developer
? <Debug ... />
: user.admin
? user.beta
? <Admin beta />
: <Admin />
: user.beta
? <Customer beta />
: <Customer />
With match
it becomes
const userTypeViewMatching = match( {
developer: () => <Debug />,
adminBeta: () => <Admin beta />,
admin: () => <Admin />,
userBeta: () => <Customer beta />,
_: () => <Customer />
} );
const ViewType = ( { userCase } ) =>
userTypeViewMatching( {
...userCase,
adminBeta: userCase.admin && userCase.beta,
customerBeta: !userCase.admin && userCase.beta
} );
There is an additional option matchAll
that will let you turn
const WeatherCard = ({ sunny, cloudy, windy, rain, snow }) => (
<Card>
{sunny && <SunIcon />}
{cloudy && <CloudIcon />}
{windy && <WindIcon />}
{rain && <RainIcon />}
{snow && <SnowIcon />}
</Card>
);
into
const weatherCardMatcher = match(
{
sunny: SunIcon,
cloudy: CloudIcon,
windy: WindIcon,
rain: RainIcon,
snow: SnowIcon
},
{ matchAll: true }
);
const WeatherCard = props => <Card>{weatherCardMatcher(props)}</Card>;
Usage
match( {
'a': 1,
'b': 2
}, 'a' );
// => 1
Will return undefined if no match is found
match( {
'a': 1,
'b': 2
}, 'c' );
// => undefined
Will return a default value when no match is found if a default key/value is in the matchClauses
match( {
'a': 1,
'b': 2,
_: 'default' // <- '_' is the default `defaultKey`
}, 'c' );
// => 'default'
Match can be partially applied with just the matchClauses ahead of time.
const requestStatus = match( {
200: 'success',
404: 'JSON not found',
_: 'Request Failed'
} );
const res = await fetch( jsonService )
requestStatus( res.status )
If the matching value is a function, it will be called with the testExpression
const getVectorLength = match( {
z: ( { x, y, z } ) => Math.sqrt(x ** 2 + y ** 2 + z ** 2),
y: ( { x, y } ) => Math.sqrt(x ** 2 + y ** 2 ),
_: vector => vector.length
} );
getVectorLength({x: 1, y: 2, z: 3})
// => 3.74165
<Fetch lazy url="https://api.github.com/users/easilyBaffled">
{ // Fetch is a render prop that passes the fetch status (`{loading, data, error}`) to its child
match( {
data: ( { data } ) => <pre>{JSON.stringify(data, null, 2)}</pre>
loading: () => <h1>...Loading</h1>,
error: ({ error }) => <h1>{error.message}</h1>
} )
}
</Fetch>
API
Match a value against a set of keys and produce the associated value.
The value may be a primitive, in which case it is matched directly against the keys of the matchClauses
object.
The value may also be an object in which case, the keys in the object, whose values are not empty are used to match against the matchClauses
.
Arguments
matchClauses
(Object): an object whose keys will be matched against. A default value, whose key is indicated by defaultKey, can be provided in the case that there is no matchtestExpression
(Object|boolean|number|string): a value that will be matched against the keys of matchClauses[options={}]
(Object): allow the user to set the defaultKey and matchAll case;[options.defaultKey=_]
(string): The key used for the default value in the matchClauses.[options.matchAll=false]
(boolean): If truematch
will return an array of all matches otherwise it will return just the first match
Returns
(undefined|*): Returns undefined if there is no match, otherwise returns the matching value(s)