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

TypeScript方法装饰器如何限制函数含任意位置可选参数c?:T

TypeScript装饰器约束:仅允许修饰带指定可选参数的函数

要让@method装饰器仅允许修饰**包含被@param标记的可选参数c?: T**的函数,你之前尝试的[...any[], T?, ...any[]]写法无效,因为TypeScript不支持中间包含可选元素的元组语法。下面是可行的解决方案:

1. 定义编译时类型约束

用递归条件类型检查函数参数列表中是否存在T | undefined类型的参数(对应可选的c?: T):

// 递归检查参数元组中是否存在T | undefined类型的元素
type IncludesOptional<T, Args extends any[]> = Args extends [infer First, ...infer Rest]
  ? First extends T | undefined
    ? true
    : IncludesOptional<T, Rest>
  : false;

// 约束函数必须包含至少一个可选的T类型参数
type HasOptionalC<T> = (...args: any[]) => any extends infer F
  ? F extends (...args: infer Args) => any
    ? IncludesOptional<T, Args> extends true
      ? F
      : never
    : never
  : never;

2. 修改@method装饰器

更新装饰器的泛型约束,同时加入运行时检查,确保函数确实被@param标记:

const contexts = new WeakMap<object, number>();

// 给method添加泛型T,明确约束的参数类型
function method<T>() {
  return <F extends HasOptionalC<T>>(
    target: any,
    key: string | symbol,
    descriptor: TypedPropertyDescriptor<F>
  ): TypedPropertyDescriptor<F> => {
    // 运行时验证:确保方法存在被@param标记的参数
    if (!contexts.has(target[key])) {
      throw new Error(`方法 "${String(key)}" 必须包含一个被@param装饰的可选参数`);
    }
    return descriptor;
  };
}

function param(
  target: Object,
  key: string | symbol,
  index: number
) {
  const method = target[key];
  contexts.set(method, index);
}

3. 使用示例

先定义T的具体类型,再在类中使用装饰器:

// 示例:定义T为字符串类型
type T = string;

class C {
  // ❌ 编译报错,运行时也会抛出错误:无符合要求的参数
  @method<T>()
  f(a: number, b: string, d?: boolean, e?: number) {
  }

  // ✅ 编译通过,运行时正常:包含被@param标记的可选参数c?: T
  @method<T>()
  g(a: number, b: string, @param c?: T, d?: boolean, e?: number) {
  }
}

关键说明

  • 编译时约束:通过HasOptionalC<T>类型强制函数参数列表中存在可选的T类型参数,不符合的函数会在编译阶段直接报错。
  • 运行时检查:利用WeakMap记录被@param标记的方法,在@method中做二次验证,避免绕过类型检查的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:36:24