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

TypeScript中使用类装饰器免new实例化类,如何消除调用报错?

问题背景

我们想在TypeScript中实现无需new关键字就能实例化类的功能。参考相关装饰器代码实现后,JavaScript运行正常,但TypeScript会提示类不可调用的错误——即便实际运行时能正常生成实例。

现有代码

类装饰器代码

var classy = function classy() {
    return function (Class) {
        var _Class = function _Class() {
            for (var _len = arguments.length, rest = Array(_len), _key = 0; _key < _len; _key++) {
                rest[_key] = arguments[_key];
            }

            return new(Function.prototype.bind.apply(Class, [null].concat(rest)))();
        };
        _Class.prototype = Class.prototype;
        return _Class;
    };
};

TypeScript使用代码

@classy()
class Someone{
    constructor(private name: string){}
}
debugger
let some1 = new Someone("john");
let some2 = Someone("joe")  // 实际能生成Someone实例,但TypeScript报错:类不可调用
解决方法

要消除TypeScript的报错,核心是给装饰器添加正确的类型定义,让TypeScript明确:被装饰后的类既可以用new实例化,也可以直接调用。

步骤1:给classy装饰器补充TypeScript类型

修改装饰器代码,添加类型声明并简化逻辑:

// 定义普通类构造函数类型
type Constructor<T = {}> = new (...args: any[]) => T;
// 合并构造函数与可调用函数的类型
type CallableConstructor<T> = Constructor<T> & ((...args: any[]) => T);

function classy(): <T extends Constructor>(target: T) => CallableConstructor<T> {
    return function <T extends Constructor>(Class: T) {
        const _Class = function (...args: any[]) {
            return new (Class.bind(null, ...args))();
        } as CallableConstructor<T>;
        
        // 继承原类原型链
        _Class.prototype = Class.prototype;
        // 复制原类的静态属性/方法(避免丢失静态成员)
        Object.assign(_Class, Class);
        
        return _Class;
    };
}

步骤2:修改使用代码

现在使用装饰器后,TypeScript能正确识别类的可调用特性,不会再报错:

@classy()
class Someone{
    constructor(private name: string){}
}

let some1 = new Someone("john");
let some2 = Someone("joe"); // TypeScript不再报错,确认这是Someone实例
console.log(some1 instanceof Someone); // true
console.log(some2 instanceof Someone); // true
原理说明
  • Constructor<T> 定义了标准类构造函数的类型,要求必须用new调用。
  • CallableConstructor<T> 将构造函数类型与普通函数类型合并,让TypeScript知晓这个类支持两种实例化方式。
  • 装饰器返回CallableConstructor<T>类型,覆盖了原类的默认类型声明,从根源消除报错。
  • Object.assign(_Class, Class)用于保留原类的静态成员,避免装饰后丢失静态属性或方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 00:54:33