如何完成这个 TS 函数的声明?

作者站长头像
站长
· 阅读数 7

我想封装一个通用的 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'
}

现在可以在 paramnever 时省略第二个参数,但是 param 不是 never 时省略第二个参数没有错误提示。我应该如何改进我的代码?

回复
1个回答
avatar
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'
}
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容