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

如何用() => TypeName解决TypeScript循环引用及变量使用问题

解决TypeScript循环引用中的类型错误问题

错误原因分析

  1. 初始类型不匹配错误:State类中_context声明为StateContext类型,但构造函数接收的是() => StateContext类型的参数,直接赋值导致类型不兼容。
  2. 子类参数传递错误:子类中传递给其他State子类的this._context是StateContext实例,但目标构造函数要求的是() => StateContext类型的参数,两者类型不匹配。

解决方案

方案一:存储上下文获取函数,通过Getter访问实例

这种方式贴合GitHub Issue #27519的建议,通过延迟获取实例规避循环引用的类型问题:

  1. 修改抽象类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; }
}
  1. 修改子类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实例,可在构造函数中调用传入的函数获取实例,传递给其他子类时将实例重新包装为函数:

  1. 修改抽象类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; }
}
  1. 修改子类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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:33:17