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

TypeScript能否通过带推断泛型的参数函数收窄可辨识联合类型?

1. 可行实现方案

你的代码首先存在笔误:narrowingFunction的第一个入参thing的类型写为了Thing,实际应该是联合类型Things。
目前有两种可正常运行的实现方案:

方案1:使用类型断言

你已经通过逻辑判断确保了thing的key和传入的key一致,符合NarrowedThing<Things, K>的类型要求,直接加类型断言即可:

interface Thing {
  key: 'bar'
  property: number
}

interface OtherThing {
  key: 'baz'
  property: string
}

type Things = Thing | OtherThing

type NarrowedThing<A, K> = A extends { 'key': K } ? A : never

const narrowingFunction = <K extends Things['key']>(thing: Things, key: K, callback: (thing: NarrowedThing<Things, K>) => void) => {
  if(thing.key === key) {
    callback(thing as NarrowedThing<Things, K>)
  }
}

方案2:自定义类型守卫

把判断逻辑抽为自定义类型守卫,让TS可以识别收窄逻辑:

function isMatchingThing<K extends Things['key']>(thing: Things, key: K): thing is NarrowedThing<Things, K> {
  return thing.key === key
}

const narrowingFunction = <K extends Things['key']>(thing: Things, key: K, callback: (thing: NarrowedThing<Things, K>) => void) => {
  if(isMatchingThing(thing, key)) {
    callback(thing) // 无类型报错
  }
}

2. 原始代码报错的底层原因

该功能完全可以实现,原始报错的核心原因有两个:

  • TS的控制流分析目前不支持对未绑定具体类型的泛型参数做关联收窄。泛型K在函数定义阶段还没有确定具体的字面量类型,TS没办法提前推断出thing.key === key这个判断对应的类型收缩规则,它只会单独识别thing是Things联合类型,不会把它和泛型K的约束关联起来。
  • TS的类型系统采用结构化类型设计,且泛型会在编译期擦除,运行时不存在泛型信息。如果K是联合类型(比如同时传入'bar'|'baz'作为key的类型),就算两个值相等,也没办法提前确定要收窄到哪一个具体的子类型,为了保证类型安全,TS默认不会做这种不确定的自动收窄。

内容的提问来源于stack exchange,提问作者Ben Wainwright

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 12:00:03