如何将嵌套非静态类型用作TypeScript构造函数参数类型?
类内非静态本地类型作为构造函数参数类型报错问题解决
你遇到的问题是:在类中定义了非静态的本地枚举类型Type,尝试将其作为构造函数参数类型时,TypeScript报错无法在构造函数参数中引用this,同时提示派生类构造函数中必须先调用super()才能访问this。
问题代码重现
export class CodePointBuffer extends JavaObject { public Type = (($outer) => { return class Type extends Enum<Type> { public static readonly BYTE: Type = new class extends Type { }(`BYTE`, 0); public static readonly CHAR: Type = new class extends Type { }(`CHAR`, 1); public static readonly INT: Type = new class extends Type { }(`INT`, 2); }; })(this); private readonly type: InstanceType<typeof this.Type> | null; private constructor(type: InstanceType<typeof this.Type> | null) { super(); this.type = type; } }
报错信息
'this' cannot be referenced in constructor arguments. (2333)
'super' must be called before accessing 'this' in the constructor of a derived class.(17009)
问题原因
TypeScript对构造函数的类型检查发生在super()调用之前,此时类实例还未完全初始化,this的引用是无效的。而你用InstanceType<typeof this.Type>作为参数类型,本质上是在构造函数参数阶段就试图访问实例的this,这违反了TS的初始化顺序规则。
优化实现方案
方案一:将枚举改为静态成员(推荐)
你的Type枚举本质上是所有CodePointBuffer实例共享的常量集合,完全没必要定义为非静态成员。改成静态后,直接通过类本身引用类型,避免依赖this:
export class CodePointBuffer extends JavaObject { public static Type = class Type extends Enum<Type> { public static readonly BYTE: Type = new class extends Type {}(`BYTE`, 0); public static readonly CHAR: Type = new class extends Type {}(`CHAR`, 1); public static readonly INT: Type = new class extends Type {}(`INT`, 2); }; private readonly type: InstanceType<typeof CodePointBuffer.Type> | null; private constructor(type: InstanceType<typeof CodePointBuffer.Type> | null) { super(); this.type = type; } }
方案二:将枚举提取到类外部
如果需要Type类型与类关联但不想用静态成员,可以将其移到类外部定义,之后在类内直接引用:
class CodePointBufferType extends Enum<CodePointBufferType> { public static readonly BYTE: CodePointBufferType = new class extends CodePointBufferType {}(`BYTE`, 0); public static readonly CHAR: CodePointBufferType = new class extends CodePointBufferType {}(`CHAR`, 1); public static readonly INT: CodePointBufferType = new class extends CodePointBufferType {}(`INT`, 2); } export class CodePointBuffer extends JavaObject { private readonly type: CodePointBufferType | null; private constructor(type: CodePointBufferType | null) { super(); this.type = type; } }
方案三:类型断言妥协(不推荐)
如果必须保留类内非静态的Type定义,可以用any作为参数类型,之后在构造函数内断言为目标类型。这种方式会丢失部分类型检查能力,仅作为最后选择:
export class CodePointBuffer extends JavaObject { public Type = (($outer) => { return class Type extends Enum<Type> { public static readonly BYTE: Type = new class extends Type {}(`BYTE`, 0); public static readonly CHAR: Type = new class extends Type {}(`CHAR`, 1); public static readonly INT: Type = new class extends Type {}(`INT`, 2); }; })(this); private readonly type: InstanceType<typeof this.Type> | null; private constructor(type: any) { super(); this.type = type as InstanceType<typeof this.Type> | null; } }
内容的提问来源于stack exchange,提问作者Mike Lischke
相关产品推荐
相关产品推荐

