map-fn v0.2.0
map-fn
A set of utility functions to map one type of values to another one with ease.
Installation
pnpm add map-fn -P
Basic usage
import { createMapFn } from 'map-fn';
type A = 'foo' | 'bar' | 'baz';
type B = 'FOO' | 'BAR' | 'BAZ';
const mapAB = createMapFn<A, B>({
foo: 'FOO',
bar: 'BAR'
});
console.log(mapAB('foo')); // 'FOO'
console.log(mapAB('bar')); // 'BAR'
If no corresponding value is provided then MappingError
will be thrown:
console.log(mapAB('baz')); // MappingError: Unable to map "baz", default value is not provided
You can provide alternative error message:
const mapAB = createMapFn<A, B>({
foo: 'FOO',
bar: 'BAR'
}, { errorMessage: (input: A): string => `No value found for "${input}"` });
console.log(mapAB('baz')); // MappingError: No value found for "baz"
or
const mapAB = createMapFn<A, B>({
foo: 'FOO',
bar: 'BAR'
});
console.log(mapAB('baz', { errorMessage: (input: A): string => `No value found for "${input}"` })); // Mapping error: No value found for "baz"
There are few options available to avoid MappingError
in such cases:
Provide default value in
createMapFn
:const mapAB = createMapFn<A, B>({ foo: 'FOO', bar: 'BAR' }, { defaultValue: 'BAZ' }); console.log(mapAB('baz')); // 'BAZ'
Provide default value calling mapping function:
const mapAB = createMapFn<A, B>({ foo: 'FOO', bar: 'BAR' }); console.log(mapAB('baz', { defaultValue: 'BAZ' })); // 'BAZ'
Use
customTransformer
option for custom value transformation increateMapFn
:const mapAB = createMapFn<A, B>( { foo: 'FOO' }, { customTransformer: (value: A) => B { return value === 'bar' ? 'BAZ' : 'BAR'; } } ); console.log(mapAB('bar')); // 'BAZ' console.log(mapAB('baz')); // 'BAR'
Provide
customTransformer
option calling mapping function:const mapAB = createMapFn<A, B>({ foo: 'FOO' }); const customTransformer = (value: A) => B { return value === 'bar' ? 'BAZ' : 'BAR'; }; console.log(mapAB('bar', { customTransformer })); // 'BAZ' console.log(mapAB('baz', { customTransformer })); // 'BAR'
Use
createMapFnUndefined
instead. Please note that output type will beB | undefined
(notB
):const mapAB = createMapFnUndefined<A, B>({ foo: 'FOO', bar: 'BAR' }); console.log(mapAB('baz')); // undefined
Please note that defaultValue
can also be a function similar to customTransformer
except it can't return undefined
. You can combine both customTransformer
and defaultValue
, the former takes precedence.
Reverse mapping
Sometimes you may want to make backward transformations without need to declare reversed map. createReverseMap
and createReverseMapUndefined
functions are created for this purpose. The only restriction here is that type of original map values must extend number
or string
.
const mapBA = createReverseMap<A, B>({
foo: 'FOO',
bar: 'BAR'
});
console.log(mapBA('FOO')); // 'foo'
console.log(mapBA('BAR')); // 'bar'
The same options as for basic mapping function creators are available for reverse function creators, the difference is input/output generic types are swapped.
Mapping with argument
For advanced cases one may consider using createArgumentMapFn
or createArgumentMapFnUndefined
mapping function creators. They provide additional input argument in mapping configuration:
import { createArgumentMapFn } from '../lib';
abstract class Person {
id: number;
constructor(id: number) {
this.id = id;
}
...
}
class Musician implements Person { ... }
class Poet implements Person { ...}
type PersonType = 'musician' | 'poet';
const mapPerson = createArgumentMapFn<PersonType, Person, number>({
musician: (id) => new Musician(id),
poet: (id) => new Poet(id)
});
const musician = mapPerson('musician', 1);
console.log(musician instanceof Musician); // true
console.log(musician instanceof Poet); // false
const poet = mapPerson('poet', 2);
console.log(poet instanceof Musician); // false
console.log(poet instanceof Poet); // true
Strict
Mapping functions described above don't guarantee that all input values have matched output ones (that's why defaultValue
and customTransformer
exist). If you want to control exhaustive matches between input and output values in TypeScript then strict functions come to the party:
const mapAB = createMapFnStrict<A, B>({
foo: 'FOO',
bar: 'BAR',
baz: 'BAZ'
});
The following will trigger type checking error because mapping object is incomplete:
const mapAB = createMapFnStrict<A, B>({
foo: 'FOO',
bar: 'BAR'
}); // baz property is missing
These is the full list of strict functions:
createMapFnStrict
;createMapFnStrictUndefined
;createReverseMapFnStrict
;createReverseMapFnStrictUndefined
;createArgumentMapFnStrict
;createArgumentMapFnStrictUndefined
.