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

TypeScript已类型标注的回调返回值为unknown的原因及修复方案

问题原因

变量x被推断为unknown的核心原因是TypeScript对重载原型方法的call调用推断能力有限,且你在reduce回调中使用了无类型标注的...args剩余参数:

  • Array.prototype.reduce是拥有多重重载的方法,直接通过.call调用时,TS无法自动根据你传入的回调反推参数类型
  • 无标注的...args默认被推断为类型不明确的元组,TS无法确认其是否匹配callback的入参要求,因此会将callback的调用返回值保守推断为unknown
  • 额外注意:你定义的ReduceFn<T>直接取Array<T>['reduce']的类型,由于TS对重载方法取Parameters时只会返回最后一个重载的参数列表,拿到的类型和你实际使用的「带初始值的reduce」参数并不匹配。
修复方案

不需要绕弯用Array.prototype.reduce.call,在fmap函数内部this已经被标注为TVal[]类型,直接调用实例的reduce方法即可让TS完成正确的类型推断,同时显式标注回调参数避免隐式any:

export const __skip__ = Symbol('skip');

/**
 * Filter-map. Like map, but you may omit entries by returning `__skip__`.
 */
export function fmap<TVal, TReturn>(
  this: TVal[],
  callback: (currentValue: TVal, index: number, array: TVal[]) => TReturn | typeof __skip__
): TReturn[] {
  return this.reduce((accum: TReturn[], currentValue, index, array) => {
    // x会被正确推断为 TReturn | typeof __skip__
    const x = callback(currentValue, index, array);
    if (x !== __skip__) {
      accum.push(x);
    }
    return accum;
  }, []);
}

如果你出于某些原因必须保留Array.prototype.reduce.call的写法,需要显式给.call传入泛型参数明确类型,避免TS的保守推断:

export function fmap<TVal,TReturn>(this:TVal[], callback: (currentValue: TVal, index: number, array: TVal[])=>TReturn|typeof __skip__): TReturn[] {
    return Array.prototype.reduce.call<
      TVal[],
      [callback: (accum: TReturn[], currentValue: TVal, index: number, array: TVal[]) => TReturn[], initialValue: TReturn[]],
      TReturn[]
    >(this, (accum, currentValue, index) => {
        const x = callback(currentValue, index, this);
        if (x !== __skip__) {
            accum.push(x);
        }
        return accum;
    }, []);
}
验证

修复后你的典型调用场景可以获得完全正确的类型推断:

const feeIds = [1,2,3]
const feeIdToKey: Record<number, string> = {1: 'a', 3: 'c'}
// keys被正确推断为string[],值为['a','c']
const keys = fmap.call(feeIds, id => feeIdToKey[id] || __skip__)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.11 16:16:23