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

TypeScript泛型重载传联合类型时无匹配重载及类型推断异常

问题现象

可在TypeScript Playground在线复现问题。
调用map函数时提示无匹配重载,回调参数x被TypeScript推断为number | undefined,不符合预期的纯number类型,复现代码如下:

declare const w: State<number>
const y = map(w, x => x) // 此处报错

export type ResolvedState<T> = {
  readonly status: 'resolved'
  readonly data: T
}

export type RejectedState<T> = {
  readonly status: 'rejected'
  readonly error?: Error
  readonly data?: T
}

export type PendingState<T> = {
  readonly status: 'pending'
  readonly data?: T
}

export type State<T> = ResolvedState<T> | RejectedState<T> | PendingState<T>

function map<T, U>(state: ResolvedState<T>, mapper: (data: T) => U): ResolvedState<U>
function map<T, U>(state: RejectedState<T>, mapper: (data: T) => U): RejectedState<U>
function map<T, U>(state: PendingState<T>, mapper: (data: T) => U): PendingState<U>
function map<T, U>(state: State<T>, mapper: (data: T) => U): State<U> {
  switch (state.status) {
    case 'resolved':
      return {
        status: 'resolved',
        data: mapper(state.data),
      }
    case 'rejected':
      return {
        status: 'rejected',
        error: state.error,
        data: state.data === undefined ? undefined : mapper(state.data),
      }
    case 'pending':
      return {
        status: 'pending',
        data: state.data === undefined ? undefined : mapper(state.data),
      }
  }
}

完整报错信息:

No overload matches this call.
  Overload 1 of 3, '(state: ResolvedState<number | undefined>, mapper: (data: number | undefined) => unknown): ResolvedState<unknown>', gave the following error.
    Argument of type 'State<number>' is not assignable to parameter of type 'ResolvedState<number | undefined>'.
      Type 'RejectedState<number>' is not assignable to type 'ResolvedState<number | undefined>'.
        Types of property 'status' are incompatible.
          Type '"rejected"' is not assignable to type '"resolved"'.
  Overload 2 of 3, '(state: RejectedState<number>, mapper: (data: number) => unknown): RejectedState<unknown>', gave the following error.
    Argument of type 'State<number>' is not assignable to parameter of type 'RejectedState<number>'.
      Type 'ResolvedState<number>' is not assignable to type 'RejectedState<number>'.
        Types of property 'status' are incompatible.
          Type '"resolved"' is not assignable to type '"rejected"'.
  Overload 3 of 3, '(state: PendingState<number>, mapper: (data: number) => unknown): PendingState<unknown>', gave the following error.
    Argument of type 'State<number>' is not assignable to parameter of type 'PendingState<number>'.
      Type 'ResolvedState<number>' is not assignable to type 'PendingState<number>'.
        Types of property 'status' are incompatible.
          Type '"resolved"' is not assignable to type '"pending"'.
原因分析

报错根源是现有三个重载签名都不支持接收联合类型State<T>作为入参:

  • 三个重载分别只接收ResolvedState<T>、RejectedState<T>、PendingState<T>三个独立类型,没有重载覆盖三者联合的State<T>类型场景
  • TypeScript重载匹配是逐个校验签名,传入的State<number>是三个子类型的联合,无法命中任何一个只接收单个子类型的重载,因此抛出无匹配重载的错误
  • 回调参数被推断为number | undefined是重载匹配失败后的兜底行为:TS会合并所有重载的参数类型,由于RejectedState和PendingState的data是可选属性,类型为T | undefined,合并后最终得到number | undefined
修复方法

把原本只作为实现的、接收State<T>联合类型的签名,补充为对外暴露的重载签名即可,调整后的代码如下:

// 新增该重载,覆盖传入联合类型State的场景
function map<T, U>(state: State<T>, mapper: (data: T) => U): State<U>
function map<T, U>(state: ResolvedState<T>, mapper: (data: T) => U): ResolvedState<U>
function map<T, U>(state: RejectedState<T>, mapper: (data: T) => U): RejectedState<U>
function map<T, U>(state: PendingState<T>, mapper: (data: T) => U): PendingState<U>
// 原有函数实现逻辑无需修改
function map<T, U>(state: State<T>, mapper: (data: T) => U): State<U> {
  switch (state.status) {
    case 'resolved':
      return {
        status: 'resolved',
        data: mapper(state.data),
      }
    case 'rejected':
      return {
        status: 'rejected',
        error: state.error,
        data: state.data === undefined ? undefined : mapper(state.data),
      }
    case 'pending':
      return {
        status: 'pending',
        data: state.data === undefined ? undefined : mapper(state.data),
      }
  }
}

调整后调用map(w, x => x)时,TS会正确命中新增的联合类型重载,x的类型会被推断为number,返回值类型也会正确识别为State<number>,报错消失。

内容的提问来源于stack exchange,提问作者Stav Alfi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:09:20