首页 > 解决方案 > 如何在 TypeScript 中扩展非导出类?

问题描述

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

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

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

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

import { Library } from "./library";

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

如果库“导出”了类定义,这将起作用;但如果没有导出,我会收到错误 TS2339:“typeof Library”类型上不存在属性“BaseUnexported”。

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

type BaseType = ReturnType<typeof Library.buildUnexportedInstance>

export default class Derived extends BaseType { 

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

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

我在 TS Playground 上的代码

PS这是一个简化的例子;事实上,我正在尝试从一个名为祝福的伟大库中扩展小部件。只想创建我自己的小部件,以扩展现有小部件的功能。

标签: node.jstypescriptinheritanceblessed

解决方案


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

你有一些选择,我最不推荐的一个是分叉项目并将类暴露给扩展。这在我看来是不可取的,因为您敞开心扉接受可能繁琐的手动更新,并且它使您有动力开始弄乱封闭(并且可能经过大量测试)的代码。

相反,我将组合而不是扩展视为可行(并且可能更好)的替代方案,例如装饰基类或使用您自己的构建器/导演来创建使用基类实例但在顶部具有您自己的功能的小部件。

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

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

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

推荐阅读