I'm trying to get TypeScript to correctly infer typing in the following code example:
type User = {
name: string
}
type Product = {
price: number
}
const userConfig = {
action: () => [{name: 'John'}] as User[],
}
const productConfig = {
action: () => [{price: 123}] as Product[],
}
const entityConfig = {
userConfig,
productConfig,
}
export const makeApp = <K extends string, R>({
config,
}: {
config: Record<K, {action: () => R}>
}) => {
const actions: Record<K, {action: () => R}> = Object.keys(config).reduce(
(acc, curr) => {
const c: {action: () => R} = config[curr as K]
return {
...acc,
[curr]: c.action(),
}
},
{} as any,
)
return {actions}
}
const app = makeApp({config: entityConfig})
const users = app.actions.userConfig.action() // Correctly typed as User[]
const products = app.actions.productConfig.action() // Incorrectly typed as User[] instead of Product[]
I see the following TypeScript error on line const app = makeApp({config: entityConfig})
Type '{ userConfig: { action: () => User[]; }; productConfig: { action: () => Product[]; }; }' is not assignable to type 'Record<"userConfig" | "productConfig", { action: () => User[]; }>'.
The types returned by 'productConfig.action()' are incompatible between these types.
Type 'Product[]' is not assignable to type 'User[]'.
Property 'name' is missing in type 'Product' but required in type 'User'.ts(2322)
How can I get the return types for the app.actions.userConfig.action() and app.actions.productConfig.action() calls to be inferred correctly as User[] and Product[] respectively?
const app = makeApp<string, User[] | Product[]>({config: entityConfig}), see here