如何在 TypeScript 中扩展未导出的 class?

How to extend a non-exported class in TypeScript?

在我的 TypeScript 程序中,我想扩展在库中声明的 class。诀窍是该库不会“导出”它,所以我无法直接访问它。相反,它提供了一个构建器函数,如下所示:

export namespace Library {
    class BaseUnexported { // no export here, for some reason
        public foo() { console.log("foo"); }
    }

    export function buildUnexportedInstance(): BaseUnexported {
        return new BaseUnexported();
    }
}

我正在尝试像这样扩展 class:

import { Library } from "./library";

export default class Derived extends Library.BaseUnexported {
    public bar() { console.log("bar"); }
}

如果库“导出”了 class 定义,这将起作用;但是没有出口我得到 error TS2339: 属性 'BaseUnexported' does not exist on type 'typeof Library'.

我试图从构造函数中获取类型,例如:

type BaseType = ReturnType<typeof Library.buildUnexportedInstance>

export default class Derived extends BaseType { 

而这一次得到错误TS2693:'BaseType'只引用了一个类型,但在这里被用作一个值。

所以,我的问题是:有没有办法扩展没有“export”关键字声明的 class?也许是一些基于原型的魔法? 请注意,我的目标是创建一个新的class,我想保持原来的class不变。

my code on TS Playground

P.S。这是一个简化的例子;事实上,我正在尝试从一个名为 blessed 的很棒的库中扩展小部件。只想创建我自己的小部件,以扩展现有小部件的功能。

简单的回答,你不能做你想做的事。看起来工厂的存在纯粹是为了阻止你扩展基础 class。在我看来,这是一件合理的事情,因为它肯定会阻止由您自己的代码创建的错误,这些错误会出现在基础 class.

您有一些选择,我最不推荐的是分叉项目并将 class 公开给扩展。这在我看来是不可取的,因为您会敞开心扉接受可能很乏味的手动更新,并且它会让您有动力开始搞乱封闭的(并且可能经过严格测试的)代码。

相反,我希望将组合而不是扩展作为一种可行的(并且可能更好)替代方案,例如装饰基础 class 或使用您自己的 builder/director 创建使用实例的小部件基础class 但在顶部有您自己的功能。

您不能做的是修改基本实例方法或非 public 内部结构,这可能是也可能不是您的症结所在。

我不知道你正在使用的库,这可能是不可能的(毕竟),这取决于不同库方法的输出是什么,但是,例如我可能会尝试:

// As the type doesn't exist in scope you could expose 
// it yourself with a custom `.d.ts`.

class MyWidgetLibrary implements BaseLibrary {
    private library: BaseLibrary;
    constructor(library: BaseLibrary) {
        this.library = library;
    }

    // for example create decorator methods to wrap the base widgets
}