我正在尝试创建严格类型化的函数来调用我的 API。我的想法是使用所有需要的数据创建类型,如下所示:
type ApiRoutes = {
'/user': {
POST: {
payload: { mydata: number }
response: UserData
}
DELETE: {
payload: string
response: UserData
}
GET: {
payload: string
response: UserData
}
}
}
在我的函数中使用它:
const apicall = async <
E extends keyof ApiRoutes,
T extends keyof ApiRoutes[E],
P extends ApiRoutes[E][T]['payload]
>(
endpoint: E,
method: T,
payload: P
):Promise<R extends ApiRoutes[E][T]['response> => {
//do stuff
}
然后这样称呼它:
apicall('/user', 'POST', {mydata: 5})
apicall('/user', 'DELETE', 'my text')
我的问题是我收到错误
类型“payload”不能用于索引类型“ApiRoutes[E][T]”
但是当调用 apiCall
时,我得到了正确的自动完成。你有什么想法我必须改变吗?我认为 infer 关键字可能会有所帮助,但我还没有玩过它,所以我不知道如何处理它。
回答1
我不完全确定为什么会发生这种情况......也许 TS 将方法的 values 视为通用对象而不是确切的对象(我不得不承认这似乎是一种奇怪的行为)但你可以通过引入几个来修复它正如您所指出的,带有 infer
key 的中间类型:
type Payload<E extends keyof ApiRoutes, T extends keyof ApiRoutes[E]> = ApiRoutes[E][T] extends {payload:infer P} ? P : never;
type Resp<E extends keyof ApiRoutes, T extends keyof ApiRoutes[E]> = ApiRoutes[E][T] extends {response:infer R} ? R : never;
您现在可以像这样重写您的函数:
const apicall = async <
E extends keyof ApiRoutes,
T extends keyof ApiRoutes[E],
P extends Payload<E,T>
>(
endpoint: E,
method: T,
payload: P
):Promise<Resp<E,T>> => {
//do stuff
}