如何完成这个 TS 函数的声明?
我想封装一个通用的 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
时省略第二个参数没有错误提示。我应该如何改进我的代码?
回复
1个回答
test
2024-06-25
拿走不谢
type Opts<T extends Api> = TMap[T]['param'] extends never
? [opts?: { query?: TMap[T]['query'] }]
: [opts: { param: TMap[T]['param']; query?: TMap[T]['query'] }]
function get<T extends Api>(api: T, ...args: Opts<T>): TMap[T]['data'] {
// TODO
throw 'Unimplented'
}
也可以使用函数重载,一个对外强制类型,一个对内稍微宽松一些
function get<T extends Api>(api: T, ...args: Opts<T>): TMap[T]['data'];
function get(api: Api, opts: {param?: object, query?: object} = {}): any {
// TODO
throw 'Unimplented'
}
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容