一旦我在接口中添加了方法的重载版本,我就会收到错误.但是,如果我把它放在现有版本之前,我就不会了.原因是什么?我在哪里可以获得更多关于这方面的信息?这是秩序的问题吗?还是别的什么?

interface Item {}

interface MyCache {
  // set(key: string, item: Item): void;
  // ^ uncomment the line and it works
  set(record: Record<string, Item[]>): void;
  // set(key: string, item: Item): void;
  // ^ uncomment the line and you get the errors
}

interface State {
  cache: Record<string, Item[]>;
}

function useCache<C>({
  state,
  cache,
}: {
  state: { cache: C };
  cache: { set: (cacheValue: C) => void };
}) {
  const { cache: cacheValue } = state;
  cache.set(cacheValue);
}

function doSomething(state: State, cache: MyCache) {
  useCache({ state, cache });
  // the errors ^ are ^ here
}

Playground (TS v5.3.3)

推荐答案

TypeScrip确实关心呼叫签名在overloaded function中的顺序.明显的依赖关系是,当您调用重载函数时,类型判断器会将调用解析为第一个匹配的调用签名,如果多个调用签名匹配,这可能会导致不同的行为:

declare function f(x: string | number): string;
declare function f(x: Date | number): Date;
const x = f(123);
//    ^? const x: string;

VS

declare function f(x: Date | number): Date;
declare function f(x: string | number): string;
const x = f(123);
//    ^? const x: Date;

但还有其他依赖关系.一般来说,编译器只能在您直接调用函数时执行重载解析.否则,当您从重载的函数类型推断时,它只 Select 一个调用签名.它不能 Select "最好的",因为这将需要一个复杂得多的推理算法.如第this comment on Microsoft/TypeScript#30369条所述:

一般来说,我们不能在推理的同时进行重载解析,通常会根据情况处理第一个或最后一个重载

在您的代码示例中,对useCache({ state, cache })的调用触发C generic类型参数的类型实参推理.显然,在这种情况下, Select 了第一个重载.这导致Cstring,因此是错误的.如果更改重载的顺序,这个问题就会消失.

这就是正在发生的事情.


请注意,您可以保持调用签名不变,并且仍然可以成功地调用useCache(),只要您不需要编译器将其设置为infer C.您可以自己显式地指定它,如下所示:

useCache<Record<string, Item[]>>({ state, cache }); // okay

这是可行的,因为编译器能够verify表示cache具有正确类型的调用签名.它只是不能为你推断出来.

Playground link to code

Typescript相关问答推荐

Typescript问题和缩减器状态不会在单击时添加用途.属性'状态和调度'不存在于userContextType类型上'|null'

如何在类型脚本中声明对象其键名称不同但类型相同?

如何从具有给定键列表的对象类型的联合中构造类型

如何推断类方法未知返回类型并在属性中使用它

在MessageStore对象中实现条件类型时出现TypeScrip错误

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

接口中函数的条件参数

在实现自定义主题后,Angular 不会更新视图

被推断为原始类型的交集的扩充类型的交集

记录键的泛型类型

Vue3 Uncaught SyntaxError:每当我重新加载页面时,浏览器控制台中会出现无效或意外的令牌

自定义 Select 组件的类型问题:使用带逗号的泛型类型<;T与不带逗号的<;T&>;时出错

避免混淆两种不同的ID类型

在TypeScript中扩展重载方法时出现问题

如何以类型安全的方式指定键的常量列表,并从该列表派生所挑选的接口?

定义一个只允许来自另一个类型的特定字符串文字的类型的最佳方式

无法使用prisma中的事务更新记录

错误:仅允许在‘使用服务器’文件中导出异步函数

将函数签名合并到重载中

是否有解释为什么默认情况下在泛型类型上访问的属性不是索引访问