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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:22:34