I've simplified my use case to this playground:
And here is the same code:
function createEntityComponentSystem<
Config extends {
[SystemName in SystemNames]: {
createComponent: () => Record<string, any>;
run: (
component: ReturnType<Config[SystemName]['createComponent']>,
) => void;
}
},
SystemNames extends (keyof Config) & string,
>(config: Config) {
// Create Entity Component System
}
createEntityComponentSystem({
systemA: {
createComponent: () => ({ x: 0, y: 0 }),
run: (
// Why isn't this inferred as { x: number; y: number } ?
// In fact, if I change this to:
// component: { x: string; y: string; }
// the compiler throws an error, because it KNOWS
// that component should be { x: number; y: number; }
// so why can't it infer it?
component,
// Uncomment to try:
// component: { x: string; y: string; },
) => {
},
}
});
If you're wondering why this exists in a record of SystemName of SystemNames, it's because it's for an Entity Component System. The systems are provided as a single config object, because I'm able to actual validate many type constraints between them when done this way. This is the single outlying issue I'm encountering, as inference has otherwise worked great.