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

为何TypeScript会合并类型而非按预期区分?

TypeScript泛型约束问题:根据输入输出格式限定tool类型

问题场景

定义了如下IO类型,用于描述不同格式间转换的配置规则,其中每个输入→输出格式对都对应特定的可用工具列表:

export type IO = {
  html: {
    pdf: {
      tool: {
        list: 'pandoc' | 'ebook-convert'
        base: {
            pandoc: { margin: number }
        }
      }
      base: { margin: number }
    }
    docx: {
      tool: {
        list: 'random' | 'another'
        base: {
            pandoc: { asdf?: number }
        }
      }
      base: { padding?: number }
    }
  }
  pdf: {
    html: {
      tool: {
        base: {
            pandoc: { margin?: number }
        }
      }
      base: { margin: number }
    }
    docx: {
      tool: {
        list: 'other' | 'ebook-convert'
        base: {
            pandoc: { padding?: number }
            other: { foo?: string }
        }
      }
      base: { padding: number }
    }
  }
}

编写conv函数时,希望根据输入文件的格式(从路径扩展名提取)和输出文件的格式,自动限定tool参数的可选值。但当前实现存在问题:

当调用以下代码时:

conv({
    input: { file: { path: "./my.html" } },
    output: { file: { path: "./my.docx" } },
    tool: 'pandoc', // 这里应该报错,因为html→docx不支持pandoc
})

当前错误的类型推断

TypeScript将tool的类型解析为所有格式转换的工具列表的并集:

(property) tool?: "ebook-convert" | "random" | "another" | "other" | undefined

预期的类型推断

应该仅限定为html→docx对应的工具列表:

(property) tool?: "random" | "another" | undefined

问题原因

原conv函数的泛型参数设计存在冗余,IX extends IO[I]和O extends keyof IX & string的约束没有明确建立I(输入格式)和O(输出格式)的唯一关联关系,导致TypeScript对泛型进行了宽泛的推断,合并了所有可能的工具类型。

解决方案

调整泛型参数,直接通过输入格式I和输出格式O定位到IO[I][O],精准提取当前转换路径对应的工具类型:

function conv<
  I extends keyof IO,
  O extends keyof IO[I],
  // 提取当前I→O转换对应的tool类型,不存在则为never
  Tool = IO[I][O] extends { tool: infer T } ? T : never,
  // 提取tool中的list类型,不存在则为never
  ToolList = Tool extends { list: infer L } ? L : never
>(
  props: {
    input: {
      file: {
        path: `${string}.${I}`;
      };
    };
    output: {
      file: {
        path: `${string}.${O}`;
      };
    };
    tool?: ToolList
  }
) {
  return props
}

关键修改点

  1. 简化泛型参数:直接用I和O定位到IO[I][O],避免多余的泛型变量(如原代码中的IX、W等)导致的类型宽泛推断
  2. 精准提取工具类型:通过条件类型Tool = IO[I][O] extends { tool: infer T } ? T : never获取当前转换对应的工具配置,再从中提取list类型作为tool参数的约束

验证效果

修改后,调用conv传入html转docx时:

  • tool参数只能选择'random'或'another'
  • 传入'pandoc'会触发TypeScript错误,符合预期

内容的提问来源于stack exchange,提问作者Lance Pollard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:23:20