如何用() => TypeName解决TypeScript循环引用及变量使用问题
解决TypeScript循环引用中的类型错误问题
错误原因分析
- 初始类型不匹配错误:
State类中_context声明为StateContext类型,但构造函数接收的是() => StateContext类型的参数,直接赋值导致类型不兼容。 - 子类参数传递错误:子类中传递给其他
State子类的this._context是StateContext实例,但目标构造函数要求的是() => StateContext类型的参数,两者类型不匹配。
解决方案
方案一:存储上下文获取函数,通过Getter访问实例
这种方式贴合GitHub Issue #27519的建议,通过延迟获取实例规避循环引用的类型问题:
- 修改抽象类
State:
export default abstract class State { protected readonly _logger: ILogger; protected readonly _name: StatusEnum; protected readonly _colour: string; // 存储上下文获取函数 protected readonly _contextGetter: () => StateContext; protected constructor( @inject(LoggerTypes.ILogger) logger: ILogger, name: StatusEnum, contextGetter: () => StateContext ) { this._logger = logger; this._name = name; this._contextGetter = contextGetter; this._colour = StatusColors[this._name] || StatusColors[StatusEnum.NEW]; } // 封装Getter,方便直接获取上下文实例 protected get context(): StateContext { return this._contextGetter(); } public abstract handle(): void; public Name(): StatusEnum { return this._name; } }
- 修改子类
NewState及其他子类:
export default class NewState extends State { private readonly _quoted: State; public constructor( @inject(LoggerTypes.ILogger) logger: ILogger, contextGetter: () => StateContext ) { super(logger, StatusEnum.NEW, contextGetter); // 直接传递上下文获取函数给子类构造函数 this._quoted = new QuotedState(logger, contextGetter); } public override async handle(): Promise<void> { this._logger.Log(LogLevels.debug, "NewState.handle()"); // 通过Getter访问上下文实例 await this.context.ChangeState(this._quoted); } }
方案二:直接存储上下文实例,传递时包装为函数
如果需要直接存储StateContext实例,可在构造函数中调用传入的函数获取实例,传递给其他子类时将实例重新包装为函数:
- 修改抽象类
State:
// 通过类型导入解决循环引用的类型定义问题 type StateContext = import('./StateContext').StateContext; export default abstract class State { protected readonly _logger: ILogger; protected readonly _name: StatusEnum; protected readonly _colour: string; protected readonly _context: StateContext; protected constructor( @inject(LoggerTypes.ILogger) logger: ILogger, name: StatusEnum, context: () => StateContext ) { this._logger = logger; this._name = name; // 调用函数获取实例并存储 this._context = context(); this._colour = StatusColors[this._name] || StatusColors[StatusEnum.NEW]; } public abstract handle(): void; public Name(): StatusEnum { return this._name; } }
- 修改子类
NewState:
export default class NewState extends State { private readonly _quoted: State; public constructor( @inject(LoggerTypes.ILogger) logger: ILogger, context: () => StateContext ) { super(logger, StatusEnum.NEW, context); // 将已存储的实例包装为函数传递给子类 this._quoted = new QuotedState(logger, () => this._context); } public override async handle(): Promise<void> { this._logger.Log(LogLevels.debug, "NewState.handle()"); await this._context.ChangeState(this._quoted); } }
关键注意点
- 循环引用场景下,使用函数延迟获取实例是TypeScript官方推荐的规避方案,能避免类型解析时的循环依赖问题。
- 确保所有
State子类的构造函数参数类型统一,要么都接收() => StateContext,要么根据实际调整传递方式。
内容的提问来源于stack exchange,提问作者khteh
相关产品推荐
相关产品推荐

