我在为我试图编写的库函数编写类型时遇到了麻烦.当我的函数接受原始对象时,类型似乎被正确推断,但当它被更新为接受返回相同对象的函数时,类型就被 destruct 了.

该函数接受具有以下 struct 的Options对象:

interface Options<Key, Result> {
  key: Key;
  format(key: Key): Result;
}

该类型用于创建一个buildStore函数(目前,它只是一个用于说明类型的标识函数).

function buildStore<Key, Result>(options: Options<Key, Result>) {
  return options;
}

const store = buildStore({
  key: {id: 32},
  format(key) {
    // key correctly inferrred as {id: number}
    return key.id.toString();
  }
});

// Result still correctly inferred as string
store.format({id: 10})

当我更新类型以直接传递构建器函数而不是Options对象时,这会中断:

function buildStore<Key, Result>(options: (...args: any[]) => Options<Key, Result>) {
  return options();
}

const store = buildStore(() => {
  return {
    key: {id: 32},
    format(key) {
      // key is of type "unknown"
      return key.id.toString();
    }
  }
});

// Property 'fn' does not exist on type '(...args: any[]) => Options<unknown, any>'.
store.format({id: 10})

我希望在从函数返回对象时仍能正确推断类型,但情况似乎并非如此.这是打字脚本的限制,还是我没有正确处理泛型?

推荐答案

这被证明是打字脚本中的一个错误,最初报告为microsoft/TypeScript#50687(后来重新报告为microsoft/TypeScript#53954,专门回答了这个问题).它与将函数标记为context-sensitive有关,因为编译器认为其类型可能取决于周围的代码……如果编译器检测到循环依赖关系,则这会导致推理延迟,有时甚至完全失败.

当编译器需要推断generic个类型参数,同时需要推断contextually个未注释的函数参数时,这种循环依赖关系很容易发生.在这种情况下推理失败的一般问题不能在打印脚本中完全修复,除非完全重写推理算法以实现microsoft/TypeScript#30134中描述的full 102,而且这种情况不太可能发生,因为microsoft/TypeScript#17520中的according to the language's chief architect,当前的算法"具有明显的优势,能够在不完整的代码中进行部分推断,这对IDE中的语句完成非常有益."因此,general的情况本质上是Typescript 的设计限制.

但这个问题有specific个例子是可以解决的,而且一直在稳步改善.特别是,您遇到的错误已经通过更改标记为上下文敏感的函数块体的方式在microsoft/TypeScript#50903中得到了修复.它计划与TypeScrip 5.1一起发布,在发布之前,如果需要的话,你可以使用the nightly typescript@next build.

Playground link to code using version typescript@5.1.0-dev.20230422

Typescript相关问答推荐

如何使用TypScript限制允许对JavaScript值进行的操作集?

如何将单元测试中的私有订阅变量设置为空(或未定义)?

React Hook中基于动态收件箱定义和断言回报类型

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

TypeScrip:基于参数的条件返回类型

与字符串文字模板的结果类型匹配的打字脚本

访问继承接口的属性时在html中出错.角形

如何在编译时为不带常量的参数引发错误

为什么不能使用$EVENT接收字符串数组?

如何使用Geojson模块和@Types/Geojson类型解析TypeScrip中的GeoJSON?

笛卡尔产品类型

在React中定义props 的不同方式.FunctionalComponent

TS2739将接口类型变量赋值给具体变量

使用ngfor循环时,数据未绑定到表

为什么在这种情况下,打字脚本泛型无法正确自动完成?

在抽象类构造函数中获取子类型

在Google授权后由客户端接收令牌

为什么数字是`{[key:string]:UNKNOWN;}`的有效密钥?

如何使用useSearchParams保持状态

如何在TypeScript中声明逆变函数成员?