我想封装一个通用的 get
函数:
enum Api {
allPage = 'https://api.example.com/allPage',
page = 'https://api.example.com/page/:id',
comment = 'https://api.example.com/page/:id/comment'
}
type PageComment = { content: string }
type Page = { content: string }
type TMap = {
[K in Api]: {
[Api.allPage]: {
param: never
query: { limit: number }
data: Page[]
},
[Api.page]: {
param: { id: number }
query: never
data: Page
},
[Api.comment]: {
param: { id: number }
query: { limit: number }
data: PageComment
}
}[K]
}
其中 param
是必选的 url 参数,query
是可选的查询参数,data
指定 api 的返回类型,我希望能够这样使用 get
函数:
// https://api.example.com/allPage
// 返回 Page[]
get(Api.allPage)
// https://api.example.com/page/12345/comment
// 返回 PageComment
get(Api.comment, { param: { id: 12345 } })
// https://api.example.com/page/12345/comment?limit=20
get(Api.comment, { param: { id: 12345 }, query: { limit: 20 } })
// 错误:url 参数 id 为指定
// 返回 never
get(Api.comment)
这是我现在写的:
function get<T extends Api>(
api: T,
{ param, query }:
{ param?: TMap[T]["param"], query?: TMap[T]['query'] } = {}
): TMap[T]["data"] {
// TODO
throw 'Unimplented'
}
现在可以在 param
为 never
时省略第二个参数,但是 param
不是 never
时省略第二个参数没有错误提示。我应该如何改进我的代码?
拿走不谢
也可以使用函数重载,一个对外强制类型,一个对内稍微宽松一些