I'm trying to use the "correlated union" changes in TS 4.6 to let me keep some factory functions typed when they're used by a generic factory (and their returned values, which I don't really show below because I already run into trouble with the factory functions).
I can't make it happy with the assignment at the end of this example:
type Factory<T> = () => T
type FactoryTypes = {
foo: string
thing: { size: number }
}
type NamedFactory<K extends keyof FactoryTypes = keyof FactoryTypes> = {
[P in K]: {
name: P
factory: Factory<FactoryTypes[P]>
}
}[K]
const factories: { [N in keyof FactoryTypes]: NamedFactory<N> } = {
foo: { name: "foo", factory: () => "hi" },
thing: { name: "thing", factory: () => ({ size: 456 }) },
}
function addFactory<N extends keyof FactoryTypes>(fv: NamedFactory<N>) {
factories[fv.name] = fv
}
That last line gives me:
Type 'NamedFactory<N>' is not assignable to type '{ foo: { name: "foo"; factory: Factory<string>; }; thing: { name: "thing"; factory: Factory<{ size: number; }>; }; }[N]'.
Type '{ name: N; factory: Factory<FactoryTypes[N]>; }' is not assignable to type 'never'.
The intersection '{ name: "foo"; factory: Factory<string>; } & { name: "thing"; factory: Factory<{ size: number; }>; }' was reduced to 'never' because property 'name' has conflicting types in some constituents.
Of course in real code I'd also have some way to call a factory given a name, returning a value returned by one of the named factory functions.
How can I change this code so TS is happy with storing the factory functions in an object, retaining the factory return type information?