代码之家  ›  专栏  ›  技术社区  ›  EugenSunic

打字通过后抱怨。。。args作为函数的参数

  •  0
  • EugenSunic  · 技术社区  · 2 年前

    我正在使用 fetch-mock 图书馆来构建我自己的utils。

    定义新函数并将参数传递给 fetchMock.mock 函数,我得到这个错误:

    排列参数必须具有元组类型或传递给rest 参数

    export function mockRequest(...args: any) {
      return fetchMock.mock(...args);
    }
    

    我可以严格定义争论的数量,但希望避免 ...args 让TypeScript快乐?

    我尝试过各种解决方案,比如使用.apply和进行一些强制转换,但都无济于事。

    1 回复  |  直到 2 年前
        1
  •  1
  •   Wing    2 年前

    问题

    fetchMock.mock 被键入以接受0-3个参数:

    mock(matcher: MockMatcher | MockOptions, response: MockResponse | MockResponseFunction, options?: MockOptions): this;
    mock(options: MockOptions): this;
    mock(): this;
    

    wheresrhys/fetch-mock/types/index.d.ts:L270-L294

    试图将 any 融入其中。 任何 不会阻止TypeScript检查排列的潜在长度,它只会不检查元组中的项的类型是否可用于函数参数。例如:

    function fn(a: number, b: number) {}
    
    const foo: any[] = [];
    const bar: [any, any] = ["one", "two"];
    
    fn(...foo); // Not OK ❌
    // ~~~~~~
    // A spread argument must either have a tuple type or be passed to a rest parameter.
    
    fn(...bar); // OK, even though we're passing in strings ✅
    

    TypeScript Playground

    解决方案

    错误消息告诉您解决方案(重点是我的):

    散布论点必须 具有元组类型 或者是 传递给rest参数

    让我们来探讨一下这两个问题。

    传递给rest参数

    如果函数被类型化为接受rest参数,它就会工作,因为rest参数本质上是可选参数的无限列表。但是,在您的情况下,您无法控制库的接口。因此,您将不得不使用另一个选项。

    将参数键入为元组

    元组是一个具有两个显著特性的列表。它们是:

    • 有限的 。这保证了长度将与您尝试使用的函数的参数长度相匹配。
    • 已订购 。这保证了每个索引处的值的类型将与同一索引处的函数参数相匹配。

    使用 Parameters ?

    tl;dr这不起作用,请参阅链接的GitHub问题

    TypeScript提供了一个名为 Parameters 它从传递给它的函数的参数中使用的类型构造元组类型,所以理论上你可以这样做:

    function mockRequest(...args: Parameters<typeof fetchMock.mock>) {
      return fetchMock.mock(...args);
    }
    

    TypeScript Playground

    然而,在撰写本文时, 参数 仅返回上次重载的参数(请参阅 TypeScript issue 14107 TypeScript issue 32164 )。在上述例子中, mockRequest 将被键入为不接受任何参数,因为 fetchMock.mock 没有参数。

    手动类型

    使用它会很可爱 参数 。看起来我们将不得不手动添加类型。下面是一个工作示例:

    type Overload1 = [matcherOrOptions:  MockMatcher | MockOptions, response: MockResponse | MockResponseFunction, options?: MockOptions];
    type Overload2 = [matcherOrOptions: MockOptions];
    type Overload3 = [];
    
    type Args = Overload1 | Overload2 | Overload3;
    
    function mockRequest(...args: Args) {
      return args.length === 1 ?
        fetchMock.mock(...args) :
        args.length >= 2 ?
          fetchMock.mock(...args as Overload1) :
          fetchMock.mock();
    }
    

    TypeScript Playground

    由于无法确定的原因,TypeScript无法缩小 args Overload1 符合条件 args.length >= 2 因此铸造是必要的。

        2
  •  -1
  •   noodlejs    2 年前

    尝试将args设置为数组类型。

    export function mockRequest(...args: any[]) {
        return fetchMock.mock(...args);
    }