如何在JavaScript中创建不继承Function且无类型错误的Callable对象?
解决可调用对象的CSP兼容与类型错误问题
方案1:普通类+JSDoc类型声明
不用继承Function,改用普通类,在构造函数里返回绑定了实例的函数,同时用JSDoc标注实例的可调用性,完美避开CSP问题还解决类型报错:
/** * @typedef {function(...any[]): any} CallableFunc */ /** * @typedef {Object} CallableBase * @property {(...args: any[]) => any} _call * @type {CallableFunc & CallableBase} */ class Callable { constructor() { const instance = this; // 创建绑定实例的调用函数 const callable = function(...args) { return instance._call(...args); }; // 把实例的属性方法都拷贝到函数上 Object.assign(callable, instance); // 维持原型链,保证继承正常工作 Object.setPrototypeOf(callable, new.target.prototype); return callable; } _call(...args) { console.log(this, args); } }
子类用法和你原来的完全一样,编辑器/TS会自动识别实例可以调用:
class Pipeline extends Callable { _call(...args) { // 这里写自定义逻辑 return `处理完成:${args[0]}`; } } const pipe = new Pipeline(); // 不会再报"This expression is not callable"的错误 const result = pipe("data"); console.log(result); // 输出:处理完成:data
方案2:TypeScript专属写法
如果是TS项目,直接用接口声明调用签名,配合类实现更严谨:
// 声明可调用的接口 interface Callable { (...args: any[]): any; } abstract class Callable implements Function { // 实现Function接口必填属性 readonly name!: string; readonly length!: number; constructor() { const instance = this; const callable = function(...args: any[]) { return instance._call(...args); } as unknown as Callable; Object.assign(callable, instance); Object.setPrototypeOf(callable, new.target.prototype); return callable; } // 子类必须实现这个方法 abstract _call(...args: any[]): any; // 空实现Function的其他方法,避免类型报错 apply(this: Function, thisArg: any, argArray?: any): any { return; } bind(this: Function, thisArg: any, ...argArray: any[]): any { return; } call(this: Function, thisArg: any, ...argArray: any[]): any { return; } } class Pipeline extends Callable { _call(...args: any[]) { return `TS处理结果:${args}`; } } const pipe = new Pipeline(); const result = pipe("test"); // 类型检查完全通过
核心原理
- 放弃
extends Function,避免触发CSP对Function构造函数的限制(通常和unsafe-eval相关) - 通过构造函数返回一个函数对象,同时把类实例的属性、方法拷贝过去,既保留类的继承特性,又让实例具备可调用性
- 用JSDoc/TS接口声明调用签名,让类型检查工具识别实例的可调用能力
内容的提问来源于stack exchange,提问作者Xenova
相关产品推荐
相关产品推荐

