简体   繁体   English

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

[英]How to extend a non-exported class in TypeScript?

In my TypeScript program I want to extend a class that is declared in a library.在我的 TypeScript 程序中,我想扩展在库中声明的 class。 The trick is that the library doesn't "export" it so I can not access it directly.诀窍是图书馆不会“导出”它,所以我不能直接访问它。 Instead, it provides a builder function, like this:相反,它提供了一个构建器 function,如下所示:

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

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

I'm trying to extend the class like this:我正在尝试像这样扩展 class :

import { Library } from "./library";

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

This would work if the library had "exported" the class definition;如果库“导出”了 class 定义,这将起作用; but without export I get error TS2339: Property 'BaseUnexported' does not exist on type 'typeof Library'.但如果没有导出,我会收到错误 TS2339:“typeof Library”类型上不存在属性“BaseUnexported”。

I tried to obtain the type from the constructor function like:我试图从构造函数 function 中获取类型,例如:

type BaseType = ReturnType<typeof Library.buildUnexportedInstance>

export default class Derived extends BaseType { 

And this time getting error TS2693: 'BaseType' only refers to a type, but is being used as a value here.而这一次得到错误 TS2693: 'BaseType' 仅指一种类型,但在这里被用作一个值。

So, my question is: is there a way to extend class that is declared without "export" keyword?所以,我的问题是:有没有办法扩展没有“export”关键字声明的 class ? Maybe some prototype-based magic?也许一些基于原型的魔法? Note that my goal is to create a new class, I want to leave the original class unchanged.请注意,我的目标是创建一个新的 class,我想保持原来的 class 不变。

my code on TS Playground 我在 TS Playground 上的代码

PS This is a simlified example; PS这是一个简化的例子; in fact I'm trying to extend widgets from a great library called blessed .事实上,我正在尝试从一个名为祝福的伟大库中扩展小部件。 Just want to create my own widgets which would extend functionality of existing ones.只想创建我自己的小部件,以扩展现有小部件的功能。

Simple answer, you can't do what you want to do.简单的回答,你不能做你想做的事。 It almost looks as if the factory exists purely to stop you extending the base class.看起来工厂的存在纯粹是为了阻止您扩展基础 class。 This is a reasonable thing to do in my eyes as it most certainly stops bugs created by your own code that would manifest in the base class.在我看来这是一件合理的事情,因为它肯定会阻止由您自己的代码创建的错误,这些错误会在基础 class 中体现出来。

You have some options, the one I'd least recommend would be forking the project and exposing the class to extension.你有一些选择,我最不推荐的一个是分叉项目并将 class 暴露给扩展。 This is undesirable in my eyes as you open yourself up to potentially tedious manual updates and it gives you impetus to start messing with closed (and likely heavily tested) code.这在我看来是不可取的,因为你敞开心扉接受可能乏味的手动更新,它让你有动力开始搞乱封闭(并且可能经过大量测试)的代码。

Instead I'd look toward composition over extension as a viable (and potentially better) alternative such as decorating the base class or using your own builder/director to create widgets that use an instance of the baseclass but with your own functionality on top.相反,我将组合而不是扩展视为一种可行(并且可能更好)的替代方案,例如装饰基础 class 或使用您自己的构建器/导演来创建使用基类实例但在顶部具有您自己的功能的小部件。

What you won't be able to do is modify the base instances methods or non public internals, this may or may not be a sticking point for you.您将无法做的是修改基本实例方法或非公共内部结构,这可能是也可能不是您的症结所在。

I don't know the library you're using and this may not be possible (after all that), it depends on what the output of the different library methods are but, for example I may look to try:我不知道您正在使用的库,这可能是不可能的(毕竟),这取决于不同库方法的 output 是什么,但是,例如我可能会尝试:

// 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM