gpt4 book ai didi

javascript - Typescript - 对装饰器的循环依赖

转载 作者:行者123 更新时间:2023-12-03 07:08:04 24 4
gpt4 key购买 nike

我对我的装饰器有一个循环依赖,因为我的类(class) ThingAThingB 有关系反之亦然。
我已经阅读了有关此问题的几个问题:

  • Beautiful fix for circular dependecies problem in Javascript / Typescript
  • TypeScript Decorators and Circular Dependencies

  • 但我无法为我的案例找到有效的解决方案。
    我尝试了很多人建议从 @hasOne(ThingA) 更改至 @hasOne(() => ThingA)强制延迟加载并打破依赖关系,但此解决方案不起作用,因为我无法获取构造函数名称。
    我需要构造函数的名称(例如:'ThingA')将其添加到构造函数 ThingB 的元数据中。
    按照我的原始代码(没有延迟加载修改)
    东西A
    @hasAtLeast(0, ThingB)
    export class ThingA extends RTContent {
    @IsEmail()
    email: string;
    }
    东西B
    @hasOne(ThingA)
    export class ThingB extends RTContent {
    @IsString()
    description: string;
    }
    装饰器:
    export type LinkConstraint<C extends RTContent> = {
    content: string; // name of the constructor (ex. 'ThingA')
    maxOccurrences: number;
    minOccurrences: number;
    constructor: { new(...args: any[]): C };
    }

    function constraintFactory<C extends RTContent>(minOccurrences: number, maxOccurrences: number, associated: { new(...args: any[]): C }) {
    return (constructor: Function) => {
    const constraints = Reflect.getMetadata('linkConstraints', constructor) || [];
    const constraint: LinkConstraint<C> = {
    content: associated?.name,
    minOccurrences,
    maxOccurrences,
    constructor: associated
    };
    constraints.push(constraint);
    Reflect.defineMetadata('linkConstraints', constraints, constructor)
    }
    }

    export function hasOne<C extends RTContent>(associated: { new(...args: any[]): C }) {
    return constraintFactory(1, 1, associated)
    }

    export function hasAtLeast<C extends RTContent>(minOccurrences: number, associated: { new(...args: any[]): C }) {
    return constraintFactory(minOccurrences, Infinity, associated)
    }

    最佳答案

    我看到您的装饰器实际上并没有修改构造函数,它只是运行一些副作用代码来添加一些元数据条目。因此 @decorator语法不是必须的。
    我的建议是你不要装饰 ThingA也不是 ThingB ,只需按原样导出它们。您将装饰推迟到另一个模块中,它应该是两个 ThingA 的共同父级。和 ThingB .这样循环依赖就解决了。
    例如,在 './things/index.ts'你做:

    import { ThingA } from './things/ThingA';
    import { ThingB } from './things/ThingB';

    hasOne(ThingA)(ThingB);
    hasAtLeast(0, ThingB)(ThingA);

    export { ThingA, ThingB }
    现在您的代码的其他部分可以从 './things/index.ts' 导入, 而不是直接来自 './things/ThingA(or B).ts' .这将确保在类实例化之前执行装饰。

    如果你必须使用装饰器,那么懒加载是你最好的选择。 @hasOne(() => ThingA)应该可以解决问题,但是您需要修改 hasOne 的实现因此,有点破解。
    function hasOne(target) {
    if (typeof target === "function") {
    setTimeout(() => {
    _workOnTarget(target())
    }, 0)
    } else {
    _workOnTarget(target)
    }
    }
    关键是 延迟 访问变量值。
    为了让这个 hack 起作用,我们仍然依赖于这些装饰器只是副作用的事实,不要修改构造函数。所以这不是循环依赖问题的一般解决方案。更一般的模式是惰性评估。不过更复杂的是,如果你真的需要,请在评论中询问。
    对于您的情况,上面的 impl 应该可以工作。但是你不能实例化 ThingA或 B 位于任何模块的顶层,因为它会在 setTimeout 之前发生回调,从而打破黑客。

    关于javascript - Typescript - 对装饰器的循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63953101/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com