swich
v1.2.0
Published
Switch, but better
Downloads
6
Readme
Swich
Switch but with a typo
Getting started
Install the library
npm i swich
Simple usage
Swich function accepts an array of [Pattern, Result] tuples. Pattern can be any value or custom compare function that returns any value. Result can be any value that is going to be returned or a function that is going to be executed (and the return value returned). See Usage examples and API below to learn more.
Swich returns function that accepts Value that is to be compared with Patterns.
import swich from 'swich';
const instance = swich([
['foo', 'This is foo'],
['bar', 'This is bar'],
['This is default'],
]);
instance('foo'); // 'This is foo'
instance('bar'); // 'This is bar'
instance('Lorem ipsum'); // 'This is default'
Table of contents
- Getting started
- Table of contents
- Usage examples
- Simple matching
- Pattern matching
- Custom compare functions
- Comparison with true
- Multiple defaults
- Returning all matches instead of first
- Non-strict equality
- Accepting truthy Pattern function return
- Catching Pattern function errors
- Perform regex replace on return value
- Calling the Result function
- createSwich function
- Custom matchers
- Custom result getters
- Comparator functions
- Fallthrough
- API
- Development
- Changelog
Usage examples
Simple matching
const instance = swich([
['foo', 'This is foo'],
['bar', 'This is bar'],
['This is default'],
]);
instance('foo'); // 'This is foo'
instance('bar'); // 'This is bar'
instance('Lorem ipsum'); // 'This is default'
Pattern matching
You can use RegExp as Patterns. They are going to be matched against provided Value (non-string values matching against regex always results in false - no errors are thrown)
const instance = swich([
[/fo./, 'This is foo'],
[/.ar/, 'This is bar'],
['This is default'],
]);
instance('foo'); // 'This is foo'
instance('xar'); // 'This is bar'
instance('Lorem ipsum'); // 'This is default'
Custom compare functions
If the Pattern is a function it's going to be called with provided Value. Matching succeeds when the function returns truthy value.
const instance = swich([
[1, 'This is one'],
[2, 'This is two'],
[value => value > 2, 'This is more than two'],
['This is default'],
]);
instance(1); // 'This is one'
instance(2); // 'This is two'
instance(10); // 'This is more than two'
instance(-2); // 'This is default'
instance('Lorem ipsum'); // 'This is default'
Comparison with true
If you don't pass any Value, true is assumed by default. It mimics the switch(true)
pattern.
const value = 'foo';
const instance = swich([
[value === foo, 'This is foo'],
[value === bar, 'This is bar'],
['This is default'],
])(); // 'This is foo'
Multiple defaults
By default (returnMany: false
, see below) only the first match (if not falling through) or last default is returned. In the case below, 'This is default 1' will never be returned.
const instance = swich([
[foo, 'This is foo'],
[bar, 'This is bar'],
['This is default 1'],
['This is default 2'],
]);
instance('xyz'); // 'This is default 2'
Returning all matches instead of first
When returnMany
flag is set to true, all matches are returned (or all defaults if no matches found)
const instance = swich([
[value => value < 3, 'This is less than three'],
[value => value > 2, 'This is more than two'],
], { returnMany: true });
instance(5); // ['This is more than two']
instance(2.5); // ['This is less than three', 'This is more than two']
const instance = swich([
[/ab./, 'This is ab'],
[/.bc/, 'This is bc'],
['Default 1'],
['Default 2'],
], { returnMany: true });
instance('abx'); // ['This is ab']
instance('abc'); // ['This is ab', 'This is bc']
instance('xyz'); // ['Default 1', 'Default 2']
Non-strict equality
By default, swich performs strict equality check between Pattern and Value. You can set strict
flag to false to change that behaviour.
const instance = swich([
['1', 'This is one'],
['2', 'This is two'],
], { strict: false });
instance(1); // 'This is one'
instance(2); // 'This is two'
Accepting truthy Pattern function return
By default, matching succeeds when the function returns truthy value. You can change that behaviour by setting acceptTruthyFunctionReturn
to false. Then all values except true
are treated as falsy.
const instance = swich([
[value => value, 'This is truthy'],
[value => !value, 'This is falsy'],
]);
instance(1); // 'This is truthy'
instance(0); // 'This is falsy'
const instance = swich([
[value => value, 'This is truthy'],
['Default'],
], { acceptTruthyFunctionReturn: false });
instance(1); // 'Default' // Truthy value is not accepted
instance(true); // 'This is truthy' // True is accepted
Catching Pattern function errors
By default, all errors thrown in Pattern function are caught. You can change that behaviour by setting catchFunctionErrors
to false.
const obj = { foo: { isTrue: true } };
const instance = swich([
[value => obj[value].isTrue, 'This is foo'],
['This is not foo'],
]);
instance('foo'); // 'This is foo'
instance('bar'); // 'This is not foo'
const instance = swich([
[value => obj[value].isTrue, 'This is foo'],
['This is not foo'],
], { catchFunctionErrors: false });
instance('foo'); // 'This is foo'
instance('bar'); // Uncaught TypeError: Cannot read property 'isTrue' of undefined
Perform regex replace on return value
You can use params from regex matching and put them in result. To enable that feature set performReplaceOnRegex
flag to true.
const instance = swich([
[/I am (.+)/, 'Their name is $1'],
['I don\'t know their name'],
], { performReplaceOnRegex: true });
instance('I am John'); // 'Their name is John'
instance('Uga buga'); // 'I don\'t know their name'
Calling the Result function
By default, if Result is a function it's going to be called with Value and it's return value is going to be returned. This partly mimics the usual usage of switch stricture.
You can disable this feature, and just return Result function as value, by setting runResultFunction
flag to false.
import swich, { gt, lt } from 'swich';
const instance = swich([
[gt(50), () => {
console.log('More than 50');
}],
[lt(0), () => {
console.log('Less than 0');
}],
[() => {
console.log('Between 0 and 50');
}],
]);
instance(120); // More than 50
instance(-20); // Less than 0
instance(20); // Between 0 and 50
import swich, { gt, lt } from 'swich';
const instance = swich([
[gt(50), value => {
return value / 2;
}],
[lt(0), value => {
return value + 10;
}],
[value => {
return value;
}],
]);
instance(120); // 60
instance(-20); // -10
instance(20); // 20
createSwich function
createSwich factory allows you to create a custom swich with different defaults. It accepts the same config object as swich function so you can overwrite your overwrites :)
import { createSwich } from 'swich';
const customSwich = createSwich({
performReplaceOnRegex: true,
catchFunctionErrors: false,
});
const instance = swich([
[/I am (.+)/, 'Their name is $1'],
[value => value.foo.bar.isTrue, 'This is foo'],
['I don\'t know their name'],
], { catchFunctionErrors: true });
instance('I am John'); // 'Their name is John'
instance('Uga buga'); // 'I don\'t know their name'
Custom matchers
You can define your own Pattern matcher.
import { createSwich, defaultMatcher } from 'swich';
const swich = createSwich({
matcher: config => (valueToMatch, pattern) => typeof pattern === 'object'
? pattern?.type === valueToMatch?.type
: defaultMatcher(config)(valueToMatch, pattern),
});
const instance = swich([
[{ type: 'foo' }, 'Type is foo'],
[{ type: 'bar' }, 'Type is bar'],
['Unknown type'],
]);
instance({ type: 'foo' }); // 'Type is foo'
instance({ type: 'bar' }); // 'Type is bar'
instance('Uga buga'); // 'Unknown type'
Custom result getters
You can define your own resultGetter that is going to be used to get the value to be returned.
import { createSwich, defaultResultGetter } from 'swich';
const swich = createSwich({
resultGetter: (config) => (valueToMatch, pattern, result) =>
defaultResultGetter(config)(valueToMatch, pattern, typeof result === 'object' ? result.value : result),
});
const instance = swich([
['foo', { value: 'Type is foo' }],
['bar', { value: 'Type is bar' }],
['Unknown type'],
]);
instance('foo'); // 'Type is foo'
instance('bar'); // 'Type is bar'
instance('Uga buga'); // 'Unknown type'
Fallthrough
Swich supports fallthrough functionality since version 1.1.0
You can force the case fallthrough by passing true
as third element of pattern tuple. This is equivalent to not adding break keyword at the end of case in switch.
const instance = swich([
[lt(10), () => console.log('Less than 10'), true],
[gt(5), () => console.log('More than 5')],
[() => console.log('I am default')],
]);
instance(6); // 'Less than 10' 'More than 5'
Please note, that by default swich will fall through to the next Result even if Pattern for that result does not match. This is the same behaviour as switch:
const instance = swich([
[lt(10), () => console.log('Less than 10'), true],
[gt(5), () => console.log('More than 5')],
[() => console.log('I am default')],
]);
instance(2); // 'Less than 10' 'More than 5'
Swich will fall through even to default Result, the same as switch. In the following example all Result functions are called:
const instance = swich([
[lt(10), () => console.log('Less than 10'), true],
[gt(5), () => console.log('More than 5'), true],
[() => console.log('I am default')],
]);
instance(2); // 'Less than 10' 'More than 5' 'I am default'
Fallthrough with stopFallThrough flag
Because the default behaviour for switch (and swich) is ridicules you can set stopFallThrough flag to true to change it. With that flag, the fallthrough will not return or trigger Result if Pattern does not match the Value. Non-matching Pattern will also stop the fall through on that element.
const instance = swich([
[lt(10), () => console.log('Less than 10'), true],
[gt(5), () => console.log('More than 5'), true],
[() => console.log('I am default')],
], { stopFallThrough: true });
instance(2); // 'Less than 10'
Fallthrough with returnMany flag
const instance = swich([
[lt(10), () => 'Less than 10', true],
[gt(5), () => 'More than 5', true],
[() => 'I am default'],
], { returnMany: true });
instance(2); // ['Less than 10', 'More than 5', 'I am default']
const instance = swich<number, string>([
[lt(10), () => 'Less than 10', true],
[gt(5), () => 'More than 5', true],
[gt(1), () => 'More than 1', true],
[() => 'I am default'],
], { returnMany: true });
instance(2); // ['Less than 10', 'More than 5', 'More than 1', 'I am default']
const instance = swich<number, string>([
[lt(10), () => 'Less than 10', true],
[gt(5), () => 'More than 5', true],
[gt(1), () => 'More than 1'],
[() => 'I am default'],
], { returnMany: true });
instance(2); // ['Less than 10', 'More than 5', 'More than 1']
Fallthrough with stopFallThrough and returnMany flags
stopFallThrough flag prevents swich from falling into default:
const instance = swich([
[lt(10), () => 'Less than 10', true],
[gt(5), () => 'More than 5', true],
[() => 'I am default'],
], { returnMany: true, stopFallThrough: true });
instance(2); // ['Less than 10']
Here, swich falls through to default, because Pattern right before it has been matched
const instance = swich<number, string>([
[lt(10), () => 'Less than 10', true],
[gt(5), () => 'More than 5', true],
[gt(1), () => 'More than 1', true],
[() => 'I am default'],
], { returnMany: true, stopFallThrough: true });
instance(2); // ['Less than 10', 'More than 1', 'I am default']
Comparator functions
Four functions for number comparisons are provided
import swich { lt, lte, gt, gte } from 'swich';
swich([
[lt(10), 'Less than 10'],
])(5); // 'Less than 10'
swich([
[lte(10), 'Less than or equal 10'],
])(10); // 'Less than or equal 10'
swich([
[gt(10), 'More than 15'],
])(15); // 'More than 15'
swich([
[gte(20), 'More than or equal 20'],
])(20); // 'More than or equal 20'
API
swich
swich function accepts two parameters: array of Pattern, Result tuples and Config.
- patterns results pairs: array array of pattern result tuples
- pattern: any Pattern to match Value with. Can also be a matching function that accepts Value as an argument and return boolean (or truthy value if
acceptTruthyFunctionReturn
is set to true which is default). Errors in Pattern function are caught by default (itt can be changed withcatchFunctionErrors
flag in config) - result: any value to be returned or function to be called when Pattern matches Value
- pattern: any Pattern to match Value with. Can also be a matching function that accepts Value as an argument and return boolean (or truthy value if
- config: object (optional) see below
- Return value: function function that accepts Value to be matched against Patterns
createSwich
- config: object (optional) see below
- Return value: function function that accepts Value to be matched against Patterns
Config
- returnMany: boolean (default: false) if set to true all matches (or all defaults if nothing matches) are going to be called (returned) (example)
- strict: boolean (default: true) indicates if strict equality comparison should be used when matching Value against Patterns (loose quality performed when set to false) (example)
- acceptTruthyFunctionReturn: boolean (default: true) if set to true, all truthy values returned from Pattern function will be treated as true, otherwise everything other than true is treated as false (example)
- catchFunctionErrors: boolean (default: true) flag indicating if errors thrown in Pattern function should be automatically caught (example)
- performReplaceOnRegex: boolean (default: false) if set to true, regex params are going to be inserted in result strings (see example)
- runResultFunction: boolean (example)
- matcher: function custom matcher (example)
- resultGetter: function custom result getter (example)
Development
- Clone the repository
npm i
Running tests
npm run test
Starting demo app
npm run demo
Changelog
1.2.0
- Improved types
- Added types exports
1.1.0
- Added fallThrough functionality
1.0.0
- Initial release