如何使用 ...rest ...spread 正确键入函数包装器以获取重载?

Posted

技术标签:

【中文标题】如何使用 ...rest ...spread 正确键入函数包装器以获取重载?【英文标题】:How to correctly type a function wrapper using ...rest ...spread to pick up overloads? 【发布时间】:2020-04-21 01:35:33 【问题描述】:

我正在尝试为Axios npm package 中的axios 函数制作一个包装器。

这个函数可以被调用

axios(config: AxiosRequestConfig) 
// When URL is contained inside config

axios(
   url: string,
   config: AxiosRequestConfig, 
)
// when it's not

我的简单包装器如下所示:

import axios from 'axios'

type AxiosArguments = Parameters<typeof axios>
const axiosWrapper = async (...args: AxiosArguments) => await axios(...args)

export default axiosWrapper

但是,TypeScript 不会以这种方式承受过载 - 当我尝试时

export const fetchSomething = () => wrappedAxios(
    url: '/url/to/something/',
    method: 'get',
)

我收到一个错误:

错误:(5, 60) TS2345: 类型参数 ' url: string; ' 不可分配给“字符串”类型的参数。

如何让它发挥作用?我宁愿学习一般情况下这样做,而不是仅仅从 Axios 导入正确的类型。

【问题讨论】:

看看这个看看参数类型别名是如何工作的:***.com/questions/51851677/… 【参考方案1】:

我可能会使用function overload:

async function axiosWrapper(config: AxiosRequestConfig): Promise<AxiosReturnValue>;
async function axiosWrapper(url: string, config: AxiosRequestConfig): Promise<AxiosReturnValue>;
async function axiosWrapper(urlOrConfig: string|AxiosRequestConfig, config?: AxiosRequestConfig): Promise<AxiosReturnValue> 
    if (typeof urlOrConfig === "string") 
        // The version with a URL
        return /*...*/;
    
    // The version without
    return /*...*/;

AxiosReturnValue 是上面的占位符。您希望它是您从包装器返回的任何内容。如果您要返回 axios 返回的内容,请使用它使用的相同返回类型。 (如果是Promise 类型,请直接使用它,而不是在Promise 中。例如,如果axios 的返回类型是Promise&lt;Something&gt;,则使用Promise&lt;Something&gt;,而不是Promise&lt;Promise&lt;Something&gt;&gt;。)

它looks like axios 使用通用返回类型AxiosResponse&lt;T&gt;。如果是,那么:

async function axiosWrapper<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
async function axiosWrapper<T>(url: string, config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
async function axiosWrapper<T>(urlOrConfig: string|AxiosRequestConfig, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> 
    if (typeof urlOrConfig === "string") 
        // The version with a URL
        return /*...*/;
    
    // The version without
    return /*...*/;

【讨论】:

我试过这个,通过type AxiosReturnValue = ReturnType&lt;typeof axios&gt; 获取 AxiosReturnValue,但我得到 Error:(9, 3) TS2739: Type AxiosResponse' is missing the following properties from type 'AxiosPromise': then, catch, [Symbol.toStringTag], finally-. 当我执行 type AxiosReturnValue = Axios.AxiosPromise 时,我得到 Error:(4, 58) TS1055: Type 'AxiosPromise' is not a valid async function return type in ES5/ES3 因为它没有引用到一个与 Promise 兼容的构造函数值。 @MichalKurz - 我已经更新了答案,我应该提到 AxiosReturnType 是一个占位符。请参阅有关返回类型的新段落以及有关AxiosResponse&lt;T&gt; 的以下内容。

以上是关于如何使用 ...rest ...spread 正确键入函数包装器以获取重载?的主要内容,如果未能解决你的问题,请参考以下文章

ES9(2018)Object Rest & Spread

Object的rest和spread方法

ES6数组扩展运算符(Rest+Spread)类方法原型方法

由 Rest参数 和 Spread扩展运算符想到的...

ES6入门一:块级作用域(let&const)spread展开rest收集

ES6新特性总结解构赋值模板字符串Symbol