You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何指定函数参数时TypeScript泛型D被推断为unknown?

TypeScript泛型推断问题:linkedSignal中D被推断为unknown的原因与优化

问题重现

原始类型定义

declare function linkedSignal<S, D>(options: {
  source: () => S;
  computation: (source: NoInfer<S>, previous?: {source: NoInfer<S>; value: NoInfer<D>}) => D;
}): D;

使用示例

linkedSignal({
    source: () => 3,
    computation: (source, previous) => {
        return 3;
    },
})

上述代码中,即使computation明确返回数值类型3,但只要声明了第二个参数previous,泛型D就会被推断为unknown。

原因分析

TypeScript的泛型推断存在优先级和依赖关系:

  1. 当computation包含previous参数时,TypeScript会优先尝试从previous的类型结构推断D,但previous.value使用了NoInfer<D>,这直接阻止了TypeScript从computation的返回值反向推导D的路径。
  2. 由于previous是可选参数,调用时没有提供具体的类型实例,TypeScript无法从previous获取D的有效类型信息,最终只能将D推断为默认的unknown。
  3. 泛型D同时作为computation的返回值类型和previous.value的类型,形成了循环依赖的推断链路,NoInfer的使用彻底打破了原本可以通过返回值推断的逻辑。

优化方案

调整类型定义结构,让TypeScript优先从computation的返回值推断D,再将该类型应用到previous.value上。核心是移除previous.value上的NoInfer<D>,并确保推断顺序合理:

declare function linkedSignal<S, D>(options: {
  source: () => S;
  computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: D }) => D;
}): D;

优化原理

  • 移除previous.value的NoInfer<D>后,TypeScript会优先从computation的返回值推断D,再将已确定的D类型应用到previous.value上,避免了循环推断冲突。
  • 保留NoInfer<S>确保S仅从source函数推断,不受computation参数类型的干扰,维持原有设计意图。

如果需要更明确地拆分推断逻辑,也可以将options拆分为交叉类型,进一步强化推断顺序:

declare function linkedSignal<S, D>(
  options: { source: () => S } & {
    computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: D }) => D;
  }
): D;

内容的提问来源于stack exchange,提问作者Matthieu Riegler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 04:42:23