如何在单独的定义文件中扩展TypeScript类定义?

47 typescript

我有一个名为leaflet的JS库,它有一个现有的TypeScript定义文件.

我希望使用一个插件,它通过一个额外的功能扩展了传单中的一些对象.

在现有的TypeScript定义文件中,对象被定义为类而不是接口.

例如

declare module L {
    function circleMarker(latlng: LatLng, options?: PathOptions): CircleMarker;

    export class CircleMarker extends Circle {
        constructor(latlng: LatLng, options?: PathOptions);
        setLatLng(latlng: LatLng): CircleMarker;
        setRadius(radius: number): CircleMarker;
        toGeoJSON(): any;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试在单独的文件中第二次定义它,那么我会收到有关"重复标识符'CircleMarker'的错误.".

declare module L {
    export class CircleMarker {
        bindLabel(name: string, options: any): CircleMarker;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有意义的,因为它是一个类而不是一个接口,但是在这种情况下有没有办法扩展这个类定义而不改变原始定义文件?

基本定义文件是通过nuget从DefinitelyTyped中提取出来的,因此我非常强烈地希望不对其进行任何更改,因为它会使更新变得更加笨拙/容易出现故障.

Wir*_*rie 25

如果您不控制原始定义文件,并且无法对其进行调整,那么很遗憾,目前TypeScript中不支持您尝试执行的操作.一个interface在打字稿是唯一的构造,允许合理的扩展,因为它只是一个编译时/语法检查,而不是运行时操作.

您不能class仅使用TypeScript 扩展具有新功能的TypeScript(并期望代码完成/ Intellisense按预期工作).当然,你可以添加功能,到prototypeCircleMarker类,但他们将无法使用智能感知,并会出错,除非你使用一个类型断言.

而不是使用any,您应该能够使用interface类型断言:

declare module L {
    export interface CircleMarkerEx {
        bindLabel(name: string, options: any): CircleMarker;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

var cm = <L.CircleMakerEx> circle.bindLabel("name", {});
Run Code Online (Sandbox Code Playgroud)

值得庆幸的是,它不会增加任何运行时开销,只需要额外的输入(双关语!).

在CodePlex上有类似"mix-ins"的建议,但它们尚未实现.即使是混合使用的建议也不会完全直接使用,并且不适用于那些并非完全用TypeScript编写的库(因为它很容易导致JavaScript代码无法安全构建,例如混合).

  • 我需要这个。对于 `class`,绝对类型库的类型不正确,最好通过增加定义来修复它。 (4认同)

bas*_*rat 13

你不能用class关键字做到这一点.有一个功能请求,您可以在这里投票:https://typescript.codeplex.com/workitem/917

但是,您可以使用interfaces变通方法(https://typescript.codeplex.com/workitem/917)中显示的类来模拟该问题.在你的情况下

declare module L {
    function circleMarker(latlng: LatLng, options?: PathOptions): CircleMarker;

    declare var CircleMarker: CircleMarkerStatic;
    export interface CircleMarkerStatic{
      new (latlng: LatLng, options?: PathOptions): CircleMarker;
    }

    export interface CircleMarker {
        setLatLng(latlng: LatLng): CircleMarker;
        setRadius(radius: number): CircleMarker;
        toGeoJSON(): any;
    }
}
Run Code Online (Sandbox Code Playgroud)

并扩展它

declare module L {
    export interface CircleMarker {
        bindLabel(name: string, options: any): CircleMarker;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 链接坏了.新链接:https://github.com/Microsoft/TypeScript/issues/2957 (4认同)