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

TypeScript模拟Java枚举:类表达式中如何传递父类构造参数?

解决方案

要在不修改类B构造函数的前提下,为父类A的构造函数传递不同参数,核心思路是绕开B的构造逻辑,直接调用A的构造函数初始化实例,同时手动设置B的私有属性。以下是两种可行的实现方式:

方法一:使用Object.create + 构造函数call

通过Object.create创建继承自B原型的实例,直接调用A的构造函数绑定到该实例,再手动赋值B的私有属性:

class A {
    public constructor(private n: number) {}
}

class B extends A {
    // 枚举常量X:给A传0
    public static readonly X = (() => {
        const instance = Object.create(B.prototype);
        // 直接调用A的构造函数,传入自定义参数
        A.call(instance, 0);
        // 手动设置B的私有属性s(用类型断言绕过TS私有属性检查)
        (instance as any).s = "abc";
        return instance as B;
    })();

    // 枚举常量Y:给A传1
    public static readonly Y = (() => {
        const instance = Object.create(B.prototype);
        A.call(instance, 1);
        (instance as any).s = "def";
        return instance as B;
    })();

    public constructor(private s: string) {
        super(1); // 此硬编码值不会被枚举实例使用
    }
}

方法二:使用Reflect.construct

Reflect.construct允许指定构造函数和原型来源,我们可以直接调用A的构造函数创建实例,同时让实例继承B的原型:

class A {
    public constructor(private n: number) {}
}

class B extends A {
    public static readonly X = (() => {
        // 创建继承自B的实例,直接调用A的构造函数传参
        const instance = Reflect.construct(A, [0], class extends B {});
        // 手动设置B的私有属性
        (instance as any).s = "abc";
        return instance as B;
    })();

    public static readonly Y = (() => {
        const instance = Reflect.construct(A, [1], class extends B {});
        (instance as any).s = "def";
        return instance as B;
    })();

    public constructor(private s: string) {
        super(1); // 此硬编码值不会被枚举实例使用
    }
}

适配Java枚举场景的完整示例

针对你提到的Java枚举转TypeScript的需求,可以将A替换为模拟java.lang.Enum的类,传递枚举名称和序号:

// 模拟Java的Enum类
class JavaEnum {
    public constructor(public readonly name: string, public readonly ordinal: number) {}
}

// 对应Java的B枚举
class B extends JavaEnum {
    public static readonly X = (() => {
        const instance = Object.create(B.prototype);
        // 传递枚举名称"X"和序号0
        JavaEnum.call(instance, "X", 0);
        (instance as any).s = "abc";
        return instance as B;
    })();

    public static readonly Y = (() => {
        const instance = Object.create(B.prototype);
        // 传递枚举名称"Y"和序号1
        JavaEnum.call(instance, "Y", 1);
        (instance as any).s = "def";
        return instance as B;
    })();

    public constructor(private s: string) {
        super("", 0); // 此默认值不会被枚举实例使用
    }
}

// 测试
console.log(B.X.name); // 输出"X"
console.log(B.X.ordinal); // 输出0
console.log(B.Y.name); // 输出"Y"
console.log(B.Y.ordinal); // 输出1

说明

  • 两种方法都绕过了B的构造函数,避免了其中硬编码的super(1)被执行;
  • 由于TypeScript私有属性的限制,需要用(instance as any)来赋值s,这在枚举转换的场景下是可接受的,因为我们是在模拟Java编译器自动生成的逻辑;
  • 所有枚举实例的类型仍然是B,符合类型检查要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:05:19