Exploring the world of TypeScript through a robustly typed system for REST requests.
Let's dive into the code:
This type is used to establish the connection between routes and their respective object types:
export interface RoutesMapping {
api1: {
users: UserApiModel
products: ProductApiModel,
}
api2: {
"other-route": OtherModel1,
"another-one-route": OtherModel2
}
}
export type ApiScope = keyof RoutesMapping
Here's the function that will handle POST requests:
export type RestApiPostResponse<T = any> = {
result: boolean
data: T
}
export function restPost<S extends keyof RoutesMapping = "api1", T extends keyof RoutesMapping[S] = keyof RoutesMapping[S]>(
route: T,
// this object is irrelevant to our focus
options: ApiRequestOptions<S, any> = {}
): Promise<RestApiPostResponse<RoutesMapping[S][T]>> {
const url = apiUtils.buildUrl(route as string, options)
const { payload, headers, isProtected } = options
return post({
url,
isProtected,
payload,
headers
});
}
To call the function, use it like this:
const data = await restPost("users")
And let TypeScript determine the return type based on scope and route.
While using the default type parameters works well:
https://i.stack.imgur.com/nQ2A7.png
The issue arises when trying to do so with another API:
const data = await restPost<"api2">("other-route")
Unfortunately, all possible types are being inferred instead of the expected one.
https://i.stack.imgur.com/G2fqZ.png
To resolve this, explicitly specify the second type parameter:
https://i.stack.imgur.com/SKI3A.png
Is there a way to achieve this without manually providing the second type parameter?
Explore more in the TypeScript playground