[英]Typescript generics type inferring
I am playing with typescript by implementing a strongly typed rest request mechanism.我通过实现强类型 rest 请求机制来玩 typescript。
Let the code speak:让代码说话:
With this type I want to define the mapping between the routes and the related type of objects:使用这种类型,我想定义路由和相关对象类型之间的映射:
export interface RoutesMapping {
api1: {
users: UserApiModel
products: ProductApiModel,
}
api2: {
"other-route": OtherModel1,
"another-one-route": OtherModel2
}
}
export type ApiScope = keyof RoutesMapping
The following function is the one I am willing to use to make POST requests下面的 function 是我愿意用来发出 POST 请求的那个
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,
// nervermind this object, is out of scope for the question
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
});
}
I expect to call this function in the following way我希望通过以下方式调用这个 function
const data = await restPost("users")
An make typescript infer the return type by inferring it by the scope and the route.一个 make typescript 通过 scope 和路由推断返回类型。
Actually, using it with the default type parameters, it works:实际上,将它与默认类型参数一起使用,它可以工作:
The problem is when I when I want to call the other api in this way:问题是当我想以这种方式调用另一个 api 时:
const data = await restPost<"api2">("other-route")
Unfortunately, it does not work and it infers all the possible types不幸的是,它不起作用,它推断出所有可能的类型
The only way to solve the problem is to explicitly add the second type parameter解决问题的唯一方法是显式添加第二个类型参数
How can I use all of this without needing to add the second type parameter in the second scenario?如何在不需要在第二种情况下添加第二个类型参数的情况下使用所有这些?
Here is a typescript playground这是一个typescript 操场
If you infer the api-key type parameter, you can actually construct a solution that does what you want:如果您推断出 api-key 类型参数,您实际上可以构建一个满足您需求的解决方案:
type Model<Route> = // Returns the model value for key Route in RoutesMapping
keyof RoutesMapping extends infer Api
? Api extends keyof RoutesMapping
? Route extends keyof RoutesMapping[Api]
? RoutesMapping[Api][Route]
: never
: never
: never
type Routes<Api> = Api extends {} ? keyof Api : never // Helper to distribute keyof over a union of objects
type AllRoutes = Routes<RoutesMapping[keyof RoutesMapping]> // Union of all route keys: 'users' | 'products' | 'other-route' | 'another-one-route'
export function restPost<Route extends AllRoutes>(
route: Route,
options?:{url:string,payload:any}
): Promise<RestApiPostResponse<Model<Route>>> {
..
}
When applied to a route string, the correct return type for restPost
is inferred, without needing to specify any type parameters:当应用于路由字符串时,会推断出
restPost
的正确返回类型,而无需指定任何类型参数:
const data = await restPost("users") // data: RestApiPostResponse<UserApiModel>
const data2 = await restPost("other-route") // data2: RestApiPostResponse<OtherModel1>
TypeScript playground TypeScript操场
Note that this assumes the route keys are unique, which seems to be the case since the api key is not passed to restPost
.请注意,这假设路由键是唯一的,这似乎是因为 api 键未传递给
restPost
。 I'm also not certain it is wise to introduce all this complexity, but at least it is possible.我也不确定引入所有这些复杂性是否明智,但至少这是可能的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.