I have the following types:
type State<C, S> = {
onEnter?: (context: C) => void;
onExit?: (context: C) => void;
transitions?: (context: C) => S | undefined;
};
class FSM<C, S extends Record<keyof S, State<C, keyof S>>> {
constructor(public readonly states: S, public readonly context: C) {
/* ... */
}
}
If I instantiate them like this:
const context = { foo: "bar" };
const f = new FSM(
{
a: { transitions: c => "b" }, // ERROR: c is implicitly any
b: { transitions: c => "a" } // ERROR: c is implicitly any
},
context
);
The compiler complains that c is implicitly any and it's unable to resolve the type of S (it comes up as never). Explicitly typing c fixes the issue, e.g:
a: { transitions: (c:typeof context) => "b" },
b: { transitions: (c:typeof context) => "a" }
Why is that? Shouldn't it be able to infer C from the context parameter of the FSM constructor?
Wild Ass Guess: Does the order of the parameters in the FSM constructor matter? Is it that it tries to resolve the type of states first and does not yet know about the type of context? If so is there a way to help the compiler "look ahead"?
NOTE: Another thing that I have a hard time understanding about this is that if I explicitly type c with a random type - e.g. transitions: (c:number)=>"a"; the compiler complains that c doesn't match the type of context. So the compiler knows what type c is but it needs me to show it that I know it too?