I am in the process of developing a function that takes multiple keys and values as input and should return an object with those keys and their corresponding values. The value types should match the ones provided when calling the function.
Currently, the code is functional, but the type checking is not precise.
I attempted to use the Factory approach, hoping that TypeScript could infer the types for me.
Below is the factory code snippet. You can also check it out on the playground here.
const maker = (subModules?: Record<string, unknown>) => {
const add = <Name extends string, Q>(key: Name, value: Q) => {
const obj = {[key]: value};
return maker({
...subModules,
...obj
})
}
const build = () => {
return subModules
}
return {
add,
build
}
}
const m2 = maker()
.add('fn', ({a, b}: { a: number, b: number }) => a + b)
.add('foo', 1)
.add('bar', 'aaaa')
.build()
// m2.foo -> 1
// m2.bar -> 'aaaa'
// m2.fn({a: 1, b: 2}) -> 3
m2
Another option available is using pipeline(playground) which may be simpler:
type I = <T extends any[]>(...obj: T) => { [P in T[number]['key']]: T[number]['value'] }
const metaMaker: I = <T extends any[]>(...subModules: T) => {
return subModules.reduce((acc, curr) => {
const op = {[curr.key]: curr.value}
return {
...acc,
...op
}
}, {}) as { [P in T[number]['key']]: T[number]['value'] }
}
const m = metaMaker(
{key: 'fn', value: ({a, b}: { a: number, b: number }) => a + b},
{key: 'foo', value: 1},
{key: 'bar', value: 'aaaa'},
)
// m.foo -> 1
// m.bar -> 'aaaa'
// m.fn({a: 1, b: 2}) -> 3
// m