Identity Functions 5 exercises
solution

Fix Inference Issues with the NoInfer Type

The solution here is to use NoInfer on the initial state:


type NoInfer<T> = [T][T extends any ? 0 : never];
interface FSMConfig<TState extends string> {
initial: NoInfer<TState>;
states: Record<
TState,
{
onEntry?: () => void;
}
>;
}

Adding NoInfer prevents anyth

Loading solution

Transcript

00:00 So you might have figured this out. The simple way to do this is to say no infer on this T state here inside the initial. And now everything starts working. So if we look at makeFiniteStateMachine here, now instead of inferring A in this type parameter,

00:17 it's inferring A or B. If we unwrap that, we can see again it's just inferring A there. This is kind of interesting. If we look at the bottom one here now, if we look at makeFiniteStateMachine, it's inferring A or B because of the states in here.

00:31 And this initial is actually erroring because it's basically saying, OK, C shouldn't be allowed. It should only be A or B in this slot. Now, you might be tempted to say, OK, why does this work? And we could dive into the reasons that this little weird tuple signature actually works here.

00:49 But I am recording this just before TypeScript 5.4 comes out. So TypeScript 5.4 beta has been released and they are basically inside TypeScript 5.4 is a new global type called no infer. And no infer behaves exactly like this. So you can think of this exercise as 5.4 ready, right?

01:08 If you need to use this before 5.4, then you can use this no infer signature that I've got for you here. Or you can use the TS tool belt library that has one inside it. But I tend to recommend actually using this instead.

01:20 But after that, you'll literally just be able to delete this code. TypeScript will have the global available for you and it will work in exactly the same way. So this is really, really important when you have multiple different inference sites in the same config object being passed in.

01:36 And this happens kind of more than you might think. This is especially true for finite state machines because you're basically declaring, OK, this object of these states here is the source of truth and I want the initial to inherit from that. But you may come across these when you're working in complex generic functions like this.