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
相关产品推荐
相关产品推荐

