TypeScript运行时检测函数签名是否匹配的解决方案
可行的运行时函数签名检查方案
1. 解析函数toString()输出对比签名
JavaScript中函数可通过toString()获取源码文本(非压缩环境下),我们可以提取目标函数的签名部分,再与传入函数的签名做对比。
示例代码:
const constant = (number: number) => number; // 提取函数签名的辅助函数 function getFunctionSignature(fn: Function): string { const str = fn.toString().trim(); // 兼容箭头函数与普通函数的格式差异 const splitChar = str.includes('=>') ? '=>' : '{'; const signaturePart = str.split(splitChar)[0].trim(); return splitChar === '=>' ? `${signaturePart} =>` : signaturePart; } class Context { execute(fn: (...args: any[]) => any) { const targetSignature = getFunctionSignature(constant); const incomingSignature = getFunctionSignature(fn); if (incomingSignature === targetSignature) { return false; } // 后续业务逻辑... } }
注意事项:
- 该方案依赖函数
toString()的输出格式,不同JS引擎、代码压缩工具(如Terser)可能篡改函数文本结构,导致签名对比失效,更适合开发环境或未压缩的生产环境。 - TypeScript的类型注解编译后会被移除,因此无法检查参数/返回值的类型信息,只能对比参数数量、参数名及函数形式(箭头/普通)。
2. 检查函数的length属性(参数数量对比)
函数的length属性会返回其形参的数量,这是一个稳定可靠的运行时属性。若只需禁止与constant参数数量一致的函数,可直接对比该值:
示例代码:
const constant = (number: number) => number; class Context { execute(fn: (...args: any[]) => any) { // constant的length为1,因为它定义了一个形参 if (fn.length === constant.length) { return false; } // 后续业务逻辑... } }
注意事项:
- 仅能检查参数数量,无法区分参数类型、返回逻辑,属于较宽松的检查方式。
- 剩余参数(如
...args)不会计入length,例如(a, ...rest) => {}的length值为1。
3. 给目标函数添加唯一标记(针对禁止特定函数)
若实际需求是禁止传入constant本身(而非所有同签名函数),可给该函数添加不可枚举的唯一属性,运行时通过检查属性存在性判断:
示例代码:
const constant = (number: number) => number; // 添加不可枚举、不可修改的唯一标记 Object.defineProperty(constant, '__isConstantFunction__', { value: true, enumerable: false, writable: false, configurable: false }); class Context { execute(fn: (...args: any[]) => any) { if ((fn as any).__isConstantFunction__) { return false; } // 后续业务逻辑... } }
注意事项:
- 仅能识别标记过的特定函数,无法阻止其他与
constant签名一致但未标记的函数。 - 标记设为不可枚举,可避免被遍历到,更隐蔽安全。
内容的提问来源于stack exchange,提问作者pinkboid
相关产品推荐
相关产品推荐

