I have a TypeScript interface
that defines the HTTP methods and query parameter types I can use on a REST endpoint (see crosswalk for details on why you might want to do this):
interface API {
'/endpoint': {
get: {a?: string, b?: string};
post: {b?: string, c?: string};
}
}
I want to define a function that takes this API type, the endpoint ('/endpoint'
) and, optionally, the HTTP verb ('get'
, 'post'
, etc.) and appropriate query parameters:
const urlMaker = apiUrlMaker<API>();
urlMaker('/endpoint')({a: 'a', b: 'b'}); // should be an error, we don't know that "a" is OK.
urlMaker('/endpoint')({b: 'b'}); // fine, "b" is always safe. Should return "/endpoint?b=b".
urlMaker('/endpoint', 'get')({a: 'a', b: 'b'});
// fine, we're explicitly using get. Should return "/endpoint?a=a&b=b".
In the case the user omits the HTTP verb, I want to accept the intersection of the query parameter types for this method (i.e. the query parameter types that can be passed to any verb).
I can get the union of the types this way:
type ParamUnion = API['/endpoint'][keyof API['/endpoint']];
// type is {a?: string, b?: string} | {b?: string, c?: string}
I'm aware of the trick for converting unions to intersections, but I'm wondering if there's a way to do that in this case that doesn't go through the union. There could, of course, be any number of HTTP verbs defined for an endpoint in addition to get
and post
(delete
, put
, patch
, etc.).