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

TS 4.4下Pipe递归类型签名两类报错的原因排查与修复求助

问题背景

我需要使用基于递归类型签名构建的pipe与compose库,该库在TS 3.4版本可正常运行,但在TS 4.4版本触发类型不匹配错误(ts:2322)无法运行。此处pipe等价于lodash和fp-ts中的flow函数,需要保留其3.4版本原有行为,修复4.4版本的兼容性问题。

错误成因

1. Pipe递归类型自引用错误

TS 4.2+版本收紧了递归条件类型的解析规则,3.4版本中惰性求值的递归类型不会被提前校验终止性,4.4版本会在类型解析阶段就检测递归的可终止性。原Pipe类型的条件分支没有对拆分出的First参数做函数类型前置校验,TS无法确定递归的终止边界,提前抛出了递归解析错误。

2. 实现与PipeFn签名不匹配

原PipeFn的泛型约束...fns: Fns & Pipe<Fns> extends AnyFunction ? Fns : never在4.4版本中的类型收窄逻辑更新,TS无法自动将用户编写的实现函数(参数和返回值默认推导为unknown)和递归计算出的Pipe函数类型做匹配,触发类型赋值错误。

修复方案

修复后的完整代码如下:

type ExtractFunctionArguments < Fn > = Fn extends  ( ...args: infer P ) => any  ? P : never

type ExtractFunctionReturnValue<Fn> = Fn extends  ( ...args: any[] ) => infer P  ? P : never

type BooleanSwitch<Test, T = true, F = false> = Test extends true ? T : F

type AnyFunction = ( ...args: any[] ) => any

export type AnyFunction1 = ( a: any ) => any

type Arbitrary = 'It is now 1554792354 seconds since since Jan 01, 1970'

type IsAny<O, T = true, F = false> = Arbitrary extends O
  ? any extends O
    ? T
    : F
  : F

// 修复递归类型校验问题,调整条件判断顺序、增加函数类型前置校验
export type Pipe<Fns extends any[], IsPipe = true, PreviousFunction = void, InitalParams extends any[] = any[], ReturnType = any> =
  Fns extends []
    ? ( ...args: InitalParams ) => ReturnType
    : Fns extends [infer First, ...infer Next]
      ? First extends AnyFunction
        ? PreviousFunction extends void
          ? Pipe<Next, IsPipe, First, ExtractFunctionArguments<First>, ExtractFunctionReturnValue<First> >
          : ReturnType extends ExtractFunctionArguments<First>[0]
            ? Pipe<Next, IsPipe, First, InitalParams, ExtractFunctionReturnValue<First> >
            : IsAny<ReturnType> extends true
              ? Pipe<Next, IsPipe, First, InitalParams, ExtractFunctionReturnValue<First> >
              : {
                ERROR: ['Return type ', ReturnType , 'does comply with the input of', ExtractFunctionArguments<First>[0]],
                POSITION: ['Position of problem for input arguments is at', Fns['length'], 'from the', BooleanSwitch<IsPipe, 'end', 'beginning'> , 'and the output of function to the ', BooleanSwitch<IsPipe, 'left', 'right'>],
              }
        : never
      : never

export type PipeFn = <Fns extends [AnyFunction, ...AnyFunction1[]]>(
  ...fns: Fns extends Pipe<Fns> ? Fns : never
) => Pipe<Fns>;

// 增加类型断言兜底实现与签名的匹配
export const pipe: PipeFn = 
  (entry: AnyFunction, ...funcs: AnyFunction1[]) =>
  (...arg: any[]) =>
    funcs.reduce((acc, item) => item(acc), entry(...arg)) as unknown as PipeFn;

修复点说明:

  • 调整Pipe类型的条件判断顺序,先判断Fns是否为空、再拆分Fns的首元素和剩余元素,同时增加First extends AnyFunction的前置校验,让TS可以正确识别递归终止逻辑,避免递归解析错误
  • 简化PipeFn的泛型约束写法,适配4.4版本的类型收窄规则
  • 将实现的参数类型从unknown改为any,同时增加as unknown as PipeFn的类型断言兜底,解决实现和签名不匹配的问题
  • 移除了不必要的item.call调用,直接调用item(acc)逻辑和原有行为完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 03:15:03