Are there any incantations to properly type the following function in typescript?
given a function
createMap()
that takes:
- a prefix (e.g.
foo
)- and a tuple of suffixes (e.g. ['a', 'b', 'c'])
calling
createMap('foo', ['a', 'b', 'c'])
return the following mapped type:{ a: 'foo.a', b: 'foo.b', c: 'foo.c', }
The function implementation is pretty straightforward, but the return type doesn't seem to be:
const createMap = <P extends string, S extends string[]>(prefix: P, suffixes: [...S]) => {
return suffixes.reduce((map, suffix) => ({
...map,
[suffix]: `${prefix}.${suffix}`,
}), {});
}
I know this is incorrect, but it would naively look something like { [K in S]:
${P}.${K in S} }
.
We can use a mapped type to compute the return type of the function. We only need to map over the elements in S
by computing the union S[number]
. Each element K
can now be used to concatenate the prefix P
with a template literal type.
const createMap = <
P extends string,
S extends string[]
>(prefix: P, suffixes: [...S]) => {
return suffixes.reduce((map, suffix) => ({
...map,
[suffix]: `${prefix}.${suffix}`,
}), {}) as { [K in S[number]]: `${P}.${K}` }
}
const result = createMap('foo', ['a', 'b', 'c'])
// ^? const result: { a: "foo.a"; b: "foo.b"; c: "foo.c"; }