Reputation: 2280
I am trying to build a strictly typed factory for my TS project and having issues figuring out if it is possible to automatically infer a schema from the passed argument.
type References = {
[name: string]: any
}
function generateReferences<T extends string | number | symbol>(
ref: References,
) {
type Return = {
[name in T]: string
}
return Object.keys(ref).reduce(
(acc, name) => ({
...acc,
[name]: `Hello from ${name}`,
}),
{},
) as Return
}
const cuteAnimals = generateReferences({
rabbits: {},
kittens: {},
})
console.log(cuteAnimals.rabbits)
console.log(cuteAnimals.kittens)
console.log(cuteAnimals.snakes) <!--- Should raise an error here
I am trying to achieve dynamic return type shaping based on the input object. Instead, TS threats return type as a simple Record.
A have found a workaround where I can define ref
object as a separate variable and pass it's typeof
as a template argument, but I'd prefer to have TS automatically infer the shape based on the input argument.
Would appreciate any ideas.
Upvotes: 2
Views: 313
Reputation: 33111
You should narrow References
type instead of declaring it explicitly:
type Return<K, V> = Record<keyof K, V>
function generateReferences<References>(
ref: References,
) {
return Object.keys(ref).reduce(
(acc, name) => ({
...acc,
[name]: `Hello from ${name}`,
}),
{} as Return<References, string>,
)
}
const cuteAnimals = generateReferences({
rabbits: {},
kittens: {},
})
console.log(cuteAnimals.rabbits)
console.log(cuteAnimals.kittens)
console.log(cuteAnimals.snakes) // error
Upvotes: 2