Typescript Function.call 类型推断问题

2021-06-17 13:31:24 +08:00
 hotwords

下面这段代码在 Typescript 4.3.3 会报错:

interface SomeMethod {
  (message: string, ...meta: any[]): void; // #1
  (data: object): void; // #2
}

declare const foo: SomeMethod;

function bar() {
  const message = 'message';
  const data = { key: 'value' };
  const meta = [data, data];

  // (message: string, ...meta: any[]): void
  foo(message, ...meta);
  foo.call(null, message, data); // TS2554: expected 2 arguments but got 3
  foo(message, ...meta);
  foo.call(null, message, ...meta); // TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.

  // (data: object): void
  foo(data);
  foo.call(null, data); // #3
}

如果交换 #1#2 两行,就会变成 #3 报错:TS2345: Argument of type '{ key: string; }' is not assignable to parameter of type 'string'.

似乎 Typescript 在推断 Function.call 的参数类型时只考虑了最后一个重载?

1994 次点击
所在节点    TypeScript
2 条回复
gyang1111
2021-06-17 16:27:37 +08:00
看着确实不能自动推断,call 类型提示是 call<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A): R;
需要在调用 call 的时候显式指明用的哪个重载,也就是<T, A extends any[], R> 这个部分,分别对应 this 的 type,参数的 type,和返回值的 type
写成这样就不会报错了
foo.call<null, [string, ...any], void>(null, message, data);
foo.call<null, [string, ...any], void>(null, message, ...meta);
hotwords
2021-06-18 08:59:21 +08:00
@gyang1111 解决了,谢谢大佬!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/783954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX