Open utterances-bot opened 2 years ago
Hi
First of really good post!
I just wonder the first declaration
declare function getUrl<API, Path extends keyof API>(path: Path, params: ExtractRouteParams<Path>);
is equivalent with the following (assuming we do not need the Path
type anymore directly)
declare function getUrl<API>(path: keyof API, params: ExtractRouteParams<typeof path>);
It would spare the whole hussle of all-or-nothing type interference (at least in this example). You may add this for sake of completeness.
Thank you for the answer. Disclaimer: I am pretty new to TS with strong C++ background. Sorry if the question is stupid
Similar question: this would be also the very same?
function getUrl<API, Path=keyof API>(path: Path, params: ExtractRouteParams<Path>)
@arvabalazs interesting question. Neither of those declarations is quite the same. For this declaration:
declare function getUrl<API>(path: keyof API, params: ExtractRouteParams<typeof path>): string;
is that typeof path
is just keyof API
, i.e. the union of all possible routes. It will never have a more specific type. In the example in the post, it will be "/users" | "/users/:userId"
. Because of the way that conditional types work in TypeScript (they distribute over unions), the net result is that the type of params
can match any of the possible paths, not just the one you called getUrl
with. Here's a playground link showing how this allows incorrect usage.
The second declaration has the same problem:
declare function getUrl<API, Path=keyof API>(path: Path, params: ExtractRouteParams<Path>): string;
In this case, if you omit the second type parameter (Path
) then it's always set to keyof API
. It won't be inferred as something more specific based on the value of path
when you call getUrl
. Here's a playground link showing this.
Until there's movement on https://github.com/microsoft/TypeScript/issues/10571, you really do need to use the techniques described in this article to get partial inference.
Thank you @dankv! Your explanation helps me a lot to build up my mental model about this language.
Generic Tips Part 1: Use Classes and Currying to create new inference sites
Effective TypeScript: Generic Tips Part 1: Use Classes and Currying to create new inference sites
https://effectivetypescript.com/2020/12/04/gentips-1-curry/