【问题标题】:Beautiful fix for circular dependecies problem in Javascript / Typescript非常适合 Javascript / Typescript 中的循环依赖问题
【发布时间】:2019-10-20 18:38:35
【问题描述】:

我在构建我正在从事的项目时偶然发现了循环依赖问题:一个小型 ORM,用于学习目的。

可以找到重现问题的最小项目here。这是一个更简单的概述:

文章

import { ManyToMany } from './ManyToMany';
import { Tag } from './Tag';

export class Article {
    @ManyToMany(Tag)
    tags: Tag[] = [];
}

多对多

//no imports
export function ManyToMany(entity) {
    …
}

标签

import { ManyToMany } from './ManyToMany';
import { Article } from './Article';

export class Tag {
    @ManyToMany(Article)
    articles: Article[] = [];
}

重要的是不要对代码进行太多更改或根本不更改,因为这会影响 DX。我不希望这个库的用户创建额外的 hacky 文件来解决这个问题。

我找到了一个讨论列表,但没有一个是优雅的:

我能找到的最佳解决方案是使用内部模块模式。此解决方案和所有其他解决方案只是针对此问题的技巧和解决方法,并没有真正解决它。

在不创建额外文件或移动代码的情况下,有没有更好、更优雅的解决方案?

【问题讨论】:

  • 你如何使用这些导入?
  • 问题是你的ManyToMany 装饰器被传递了一个值,即类对象本身。你需要它来接受一个类型,但我不知道这怎么可能。
  • 或者你不应该让它接受一个参数,而是让它内省它被调用的属性的类型声明?不幸的是,我不知道这在 TypeScript 中是否可行,但这将是理想的解决方案。
  • 一个肯定可行的解决方案是使引用变得惰性,即传递一个返回实体的函数并且不立即评估它(在属性装饰期间),但稍后当所有模块加载时,类已初始化,并正在创建第一个实例:@ManyToMany(() => Tag)
  • 我尝试了延迟加载,但它不起作用stackoverflow.com/questions/63953101/…

标签: javascript typescript decorator circular-dependency typescript-decorator


【解决方案1】:

根据 Bergi 的评论,可行的解决方案是使引用变得惰性,即传递一个返回实体的函数并且不立即评估它(在属性装饰期间),但稍后当所有模块加载时,类初始化,并且正在创建第一个实例。

我尝试在这里实现相同的https://stackblitz.com/edit/typescript-f5rm9u。请检查实现。

多对多

export function ManyToMany(entity=() => entity) {
    return function(target, name)  {
        console.log(entity.name);
    };
}

答案来源:@Bergi

【讨论】:

  • 不,Tag => Tagx => x 一样毫无意义。您的实现根本不记录任何名称。
  • 我已经使用了这个答案和你的答案@Bergi,并且还在 ManyToMany 中添加了一个 setTimeout() 并且它可以工作。唯一的问题是代码现在是异步的。
  • 不需要让它异步,推迟它直到实例被创建就足够了(或者你的装饰器应该创建的任何东西都将被执行)
  • @Bergi 请检查,stackblitz.com/edit/typescript-f5rm9u 在这里。您可以看到带有 0 个标签的文章实体的日志。另外,我们可以创建标签的实例,所以这里我们使用箭头 x=>x 或标签 => 标签表示它是指当前调用的实例。
  • 我最终提出了这个解决方案:stackblitz.com/edit/typescript-rhmdhq?file=index.ts。这是我期望在控制台中看到的
猜你喜欢
  • 1970-01-01
  • 2015-01-25
  • 2019-12-09
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
相关资源
最近更新 更多