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

如何通过类型强制两函数签名一致?含参数顺序相反场景

解决方案

一、基础场景:fnGenerator 参数顺序反向的签名兼容校验

你遇到的核心问题是泛型约束方向搞反了——原代码要求Original extends Copy(即原函数兼容复制函数),但实际需要的是Copy extends Original(复制函数兼容原函数)。以下是两种修正方式:

方式1:直接泛型约束

通过泛型明确要求复制函数必须是原函数的子类型(可赋值给原函数):

function fnGenerator<Original extends Function, Copy extends Original>(copy: Copy, original: Original) {}

function original(props:{a?:number,z:number}):number { return 2}
function copy(props:{a:number}):number { return 1}

fnGenerator(copy,original) // 编译错误指向copy,符合预期

方式2:精确参数/返回值约束(推荐)

使用TypeScript内置工具类型Parameters和ReturnType,更精确地约束复制函数的参数和返回值与原函数兼容:

function fnGenerator<Original extends (...args: any[]) => any>(
  copy: (...args: Parameters<Original>) => ReturnType<Original>,
  original: Original
) {}

function original(props:{a?:number,z:number}):number { return 2}
function copy(props:{a:number}):number { return 1}

fnGenerator(copy,original) // 编译错误指向copy,符合预期

二、实际场景:fallback装饰器的签名校验

当前装饰器代码的问题是泛型仅约束被装饰方法适配fallback函数的类型,而非反过来。我们需要在装饰器中捕获被装饰方法的类型,并强制fallback函数兼容该类型:

修正后的装饰器代码

function fallback<FallbackFn>(props: { fallback: FallbackFn }) {
  return function <OriginalFn>(
    target: any,
    propertyKey: string,
    // 通过条件类型触发错误:若fallback不兼容原方法,则要求descriptor包含不存在的属性
    descriptor: Omit<PropertyDescriptor, 'value'> & { value: OriginalFn } & (FallbackFn extends OriginalFn ? {} : { __INCOMPATIBLE__: never })
  ) {
    return descriptor;
  };
}

更精确的兼容性校验(可选)

如果需要明确区分参数不兼容还是返回值不兼容,可以扩展条件类型:

function fallback<FallbackFn extends (...args: any[]) => any>(props: { fallback: FallbackFn }) {
  return function <OriginalFn extends (...args: any[]) => any>(
    target: any,
    propertyKey: string,
    descriptor: Omit<PropertyDescriptor, 'value'> & { value: OriginalFn } & (
      // 函数兼容性规则:参数逆变,返回值协变
      Parameters<OriginalFn> extends Parameters<FallbackFn> 
        ? ReturnType<FallbackFn> extends ReturnType<OriginalFn> 
          ? {} 
          : { __ERROR__: "Fallback返回值与原方法不兼容" } 
        : { __ERROR__: "Fallback参数与原方法不兼容" }
    )
  ) {
    return descriptor;
  };
}

测试示例

class MyClass1 {
  // 触发编译错误:fallback要求z必须存在,而method1允许z可选,签名不兼容
  @fallback({fallback: (props: {x:number,z:number})=>{ return 0} })
  static method1(props:{x:number, z?: number}):number {
    return 1
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:37:03