Advanced Generics 9 exercises

Fixing the "Not Assignable" Error

The solution here highlights a limitation of TypeScript that you need to build into your mental model.

Here's the remapPerson function we started with:

export function remapPerson<Key extends keyof Person>(
key: Key,
value: Person[Key],
): Person[Key] {
if (key === "date") {

Loading solution


0:00 The solution here is a little bit annoying and shows a limitation of TypeScript's that you need to build into your mental model. When we have a remapPerson function like this and the return type is Person [Key , we're basically saying, "OK, this can be called with any key."

0:19 Weirdly, it can also be called with a union type of some of the keys to. I could say remapPerson. If I wanted to, I could manually pass in "age" | "birthdate", something like this. What this means then is I can pass either number or dates into here, so I can pass new Date().

0:42 Because of this wrinkle, TypeScript can't trust any narrowing inside a generic function. What we've got here is we've got this, if key is birthdate, then return a new Date.

1:00 What I should be able to say inside here is it should give me a proper error, if I tried to return a number for the user's birthdate, because it doesn't meet the contract in my person up here, but it's not telling me that. It basically resolves any return types inside these narrowing's as never, because it can't trust that key breaks down at this level.

1:26 What this means, if you start getting these strange errors when you're doing this narrowing inside generic functions is you need to put an as on it. If you like it, then you should have put an as on it. What we've got here is return new Date() as any.

1:41 What's the actual proper type that we should be returning there, because as any feels a little bit gross? Well, we can slap on as Person [Key . We can match the return type there, because here you can see that value is typed as Person [Key]. If I remove this now, this is still typed as Person [Key], because that's what the value is literally typed as there.

2:04 This can be a frustrating thing when you start to look at generics, especially the inside of generic functions and start to feel, "Oh dear, I'm starting to reach the levels of what TypeScript can do here.

2:17 Trust yourself, trust that when you're in these situations and as is usually fine and usually exactly what you want. These situations can be annoying, but just knowing that should make it feel a little bit easier.