【问题标题】:Return a new instance of child class from base class: circular reference从基类返回子类的新实例:循环引用
【发布时间】:2018-12-22 21:31:50
【问题描述】:

我想在基类的静态方法中创建一个子实例,如下所示:

class Baseclass {
    public static create(){
        const newInstance = new Childclass();
        return newInstance;
    }
}

class Childclass extends Baseclass {}

const anInstance = Baseclass.create();

这按预期工作。但是如果我想把每个类放到一个单独的文件中,我会得到

TypeError: Class extends value undefined is not a constructor or null

你可以看到一个例子here。 我认为这与创建某种循环引用的导入有关。但是由于这在两个类都定义在同一个文件中时有效,所以我只假设当它们在单独的文件中时它也应该以某种方式工作。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    正如我在github issue 和相关的github repository about the problem 上发现的,解决方案是将index.ts

    export { Baseclass } from './baseclass';
    // NOTE: Putting this line first causes a problem.
    export { Childclass } from './childclass';
    

    然后只引用它而不是文件。见this example

    【讨论】:

    • 一般来说它是不安全的并且依赖于模块化环境。这可能适用于 Webpack。但我预计它会因原生 ES 模块而失败(尚未检查)。
    【解决方案2】:

    BaseclassChildclass 放到不同的模块中会在它们之间创建循环引用,这是ES 模块无法解决的; Baseclass 需要导入 Childclass 才能定义,反之亦然。

    这里的问题是Baseclass。它不是真正的基类,因为它直接引用子类,而它不应该知道它的后代。如果应该有工厂方法,它可以引用this作为静态方法中的类构造函数。如果基类不应该单独使用,它可以是抽象的:

    abstract class Baseclass {
        public static create(){
            return new this();
        }
    }
    
    class Childclass extends Baseclass {}
    

    【讨论】:

    • 好吧,也许我混淆了术语,请随时编辑。但就我而言,返回Childclass 的实例而不是this 很重要,即Baseclass
    • @InsOp 解决这个问题的唯一方法是回退到 CJS require 而不是导入,因为这样导入可能会延迟和同步导入,例如const Childclass = require('...').Childclass; const newInstance = new Childclass()。这是 TS 中的一个 hack,因为它的类型不安全。这通常是 OOP 中的反模式。父母不应该知道他们的孩子。你为什么需要那个?对我来说看起来像 XY 问题。
    • 我需要工厂模式来异步创建实例。我从Baseclass 中的数据库加载数据,然后决定在create 方法中返回哪个后代的哪个实例。看我的回答,我想我找到了解决办法
    • 问题中没有提出。如果您需要它们异步,那么最好的选择可能是动态import(),它会被延迟评估并且不会产生循环依赖。我认为该解决方案是一种 hack,因为它依赖于其他机制来解决循环依赖关系(github.com/ashleydavis/… 回退到require)。我刚刚使用原生 ESM 进行了检查,但未能解决。
    • Stackblitz 使用 SystemJS 作为模块。它不使用本机模块,因此不具有代表性。我已经用 Chrome 和 Node 原生模块检查了这个设置。它适用于 Chrome 实现,但无法在 Node 中解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 2015-12-04
    相关资源
    最近更新 更多