I have these general definitions:
type Module<P extends Payloads, C extends Children> = {
payloads: P;
children: C;
};
type Children = Record<string, any>; // some values will be nested Modules
type Payloads = Record<string, any>;
type ExtractPayloads<M extends Module<any, any>> = M extends Module<infer P, any> ? P : never;
type ExtractChildren<M extends Module<any, any>> = M extends Module<any, infer C> ? C : never;
Basically, Modules are types that specify a children
type, which can contain nested Modules.
I have this type that can generate Action
s based on a Module's payload
type:
type ModuleRootActions<
MODULE extends Module<any, any>,
PAYLOADS = ExtractPayloads<MODULE>,
> = {
[NAME in keyof PAYLOADS]: {
type: NAME;
payload: PAYLOADS[NAME];
};
}[keyof PAYLOADS];
Next, I have a recursive type that helps me generate Action
s for ALL Modules in a Module's tree (i.e., including its child modules, and grandchildren, etc):
type AllModuleActions<
MODULE extends Module<any, any>,
CHILDREN = ExtractChildren<MODULE>,
> =
| ModuleRootActions<MODULE>
| {
[KEY in keyof CHILDREN]: CHILDREN[KEY] extends Module<any, any>
? AllModuleActions<CHILDREN[KEY]>
: never;
}[keyof CHILDREN];
Finally, I have these concrete examples:
type C = Module<{
"incrementBy": number;
}, {}>;
type B = Module<{
"setIsSignedIn": boolean;
}, {
c: C;
}>;
type A = Module<{
"concat": string;
"setIsDarkMode": boolean;
}, {
b: B;
}>;
All my types thus far are correct -- I've verified this manually. Now, I'm writing a function that takes in an Action
of a generic Module
. I can successfully define these types:
type ConcreteAction<M extends Module<any, any>> = AllModuleActions<M>;
const concreteAction: ConcreteAction<A> = {
type: "concat",
payload: "str",
}
But once I try to put them in a generic function, I get the error in the title.
const composedReducer = <MODULE extends Module<any, any>>(
action: AllModuleActions<MODULE>,
) => {
if (action) {
}
};
You'll notice in the Playground link that action
has the error: "Type instantiation is excessively deep and possibly infinite". I assume this is happening because the MODULE
type is generic, and it's possible that there could be cycles in the Module
definition, even though semantically I know that it's a tree.
How can I fix this error? Is there a way to tell the compiler that the graph will always be a tree and never contain infinite cycles?