You can use the extends keyword to narrow the scope of a generic to make it more useful. Here for instance, we want to get a deep value from an object
const result = getDeepValue(obj, "bar", "d")
getDeepValue is gonna take in the object and then take in the two keys that it's gonna use to then grab the value. So we can use extends here to say the FirstKey needs to be keyof Obj, which is our object.
export const getDeepValue = <Obj, FirstKey extends keyof Obj, SecondKey>(
obj: Obj,
firstKey: FirstKey,
secondKey: SecondKey
) => {
return {} as any
}
And now we get some nice auto-complete on this deep value. Which is either foo or bar. Let's say it's bar for now.
const result = getDeepValue(obj, "bar", "d")
Now this second key is now going to extends keyof Obj[FirstKey].
export const getDeepValue = <
Obj,
FirstKey extends keyof Obj,
SecondKey extends keyof Obj[FirstKey]
>(
obj: Obj,
firstKey: FirstKey,
secondKey: SecondKey
) => {
return {} as any
}
And that means that when we select bar, this third argument is going to be c or d.
const result = getDeepValue(obj, "bar", "d")
And when we select foo, it will be either a or b.
const result = getDeepValue(obj, "foo", "a")
So let's say it's a for instance. We now need to work out what the result is going to be, because it's currently typed as any. So here in the return type definition we can just say Obj[FirstKey][SecondKey] just like property access in JavaScript.
export const getDeepValue = <
Obj,
FirstKey extends keyof Obj,
SecondKey extends keyof Obj[FirstKey]
>(
obj: Obj,
firstKey: FirstKey,
secondKey: SecondKey
): Obj[FirstKey][SecondKey] => {
return {} as any
}
Now the result is a Boolean. And if I change the third argument to b, then it becomes a number.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.