typescript 类型“(a:number,b:string)=>string'不能赋值给类型'(...args:(string|number)[])=>string'

iezvtpos  于 2023-05-01  发布在  TypeScript
关注(0)|答案(1)|浏览(382)

下面是一个makeSafe函数,它在下面的测试中被调用。

import { expect, it } from 'vitest';
import { Equal, Expect } from '../helpers/type-utils';

const makeSafe =
  <Args extends string | number, R>(func: (...args: Args[]) => R) =>
  (
    ...args: Args[]
  ):
    | {
        type: 'success';
        result: R;
      }
    | {
        type: 'failure';
        error: Error;
      } => {
    try {
      const result = func(...args);

      return {
        type: 'success',
        result,
      };
    } catch (e) {
      return {
        type: 'failure',
        error: e as Error,
      };
    }
  };

it("Should properly match the function's arguments", () => {
  const func = makeSafe((a: number, b: string) => {
    return `${a} ${b}`;
  });

  // @ts-expect-error
  func();

  // @ts-expect-error
  func(1, 1);

  func(1, '1');
});

typescript推断args为(字符串|number)[],因此我得到了这个错误
ts-error

Argument of type '(a: number, b: string) => string' is not assignable to parameter of type '(...args: (string | number)[]) => string'.
  Types of parameters 'a' and 'args' are incompatible.
    Type 'string | number' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.(2345)

但是使用下面的makeSafe函数的类型定义,typescript将args推断为文字元组[a:number,b:string],所以我没有得到任何错误,测试通过

import { expect, it } from 'vitest';
import { Equal, Expect } from '../helpers/type-utils';

const makeSafe =
  <Args extends (string | number)[], R>(func: (...args: Args) => R) =>
  (
    ...args: Args
  ):
    | {
        type: 'success';
        result: R;
      }
    | {
        type: 'failure';
        error: Error;
      } => {
    try {
      const result = func(...args);

      return {
        type: 'success',
        result,
      };
    } catch (e) {
      return {
        type: 'failure',
        error: e as Error,
      };
    }
  };

这两种解决方案的唯一区别是typescript如何推断参数args,为什么typescript要这样做?

xzlaal3s

xzlaal3s1#

当您定义Args extends string | number并将其用作...args: Args[]时,它实际上可以按预期工作。如果你传递(a: number, b: string)Args计算为string | number,你得到string | number[]。所以基本上你的泛型只计算数组的一个元素,而不是整个数组。然而,在第二种情况下,您期望的是一个extends string | number的元素数组,这使编译器能够完全理解...args的类型。

相关问题