【问题标题】:Typescript: Adding additional overloads to an existing abstract class打字稿:向现有抽象类添加额外的重载
【发布时间】:2021-06-03 04:27:21
【问题描述】:

我正在为包 Leaflet.Editable 开发一组肯定类型的定义。 Leaflet 值得注意的是,它使用部分自定义的类实现来允许在纯 JavaScript as seen here 中扩展现有类型。只需在代码中的任意位置调用 import 'Leaflet.Editable' 即可为现有的 Leaflet 类添加新功能,例如启用和禁用某些图层的编辑功能。

它没有在 TypeScript 中实现,因此打字是在 @types/leaflet 中实现的,所以我正在开发的包 (@types/leaflet-editable) 必须导入传单命名空间并扩展现有类型。

我必须扩展现有类型而不是添加新类型,因为还有其他库(例如 react-leaflet)使用这些类型。

例如,通过扩展MapOptions 类型(通过merging the interfaces),我能够向react-leafletMapComponent 组件添加新属性,因为它的props 扩展了Leaflet.MapOptions。如果我要创建一个新类型EditableMapOptions,它不会被react-leaflet 扩展,因此我无法将这些属性添加到MapComponent

我能够扩展几个现有接口,并添加新的接口,例如VertexEventHandlerFn(它表示提供VertexEvent 的事件回调)。

问题在于@types/leaflet 如何实现map.on('click', (event: LeafletEvent) => {}) 函数。这是来自the DefinitelyTyped repo的sn-p:

export abstract class Evented extends Class {
    /**
     * Adds a listener function (fn) to a particular event type of the object.
     * You can optionally specify the context of the listener (object the this
     * keyword will point to). You can also pass several space-separated types
     * (e.g. 'click dblclick').
     */
    // tslint:disable:unified-signatures
    on(type: string, fn: LeafletEventHandlerFn, context?: any): this;
    on(type: 'baselayerchange' | 'overlayadd' | 'overlayremove',
        fn: LayersControlEventHandlerFn, context?: any): this;
    on(type: 'layeradd' | 'layerremove',
        fn: LayerEventHandlerFn, context?: any): this;
    ...

如您所见,它使用了一个抽象类,该类实现了一个通用定义,当用户包含多个由空格分隔的事件时,以及几个特定事件,当提供特定参数时,包括为其事件处理程序正确键入的事件。

我想在其中添加我的函数,但我找不到任何方法来向现有抽象类添加额外的重载。这里要注意的是,on 的所有这些重载都是由 Leaflet 中的同一行代码实现的,因此向抽象类添加新方法所面临的问题(稍后将由相关的 JavaScript 未实现)不会存在于此。

我尝试简单地尝试重新声明 abstract class Evented 以向其添加更多方法,但 TypeScript 告诉我它已经定义。我的研究只发现 TypeScript 文档表明我应该使用 mixins,我不能这样做,因为我需要修改现有的类,并且创建一个新的类并不能解决问题。

Here is my current TypeScript implementation of leaflet-editable so far.

【问题讨论】:

    标签: javascript typescript types leaflet definitelytyped


    【解决方案1】:

    documentation for module augmentation 中可能不清楚,但如果您想合并到名为classinstance 类型,可以通过添加到interface 来实现与class 同名。当你写class Foo {}时,它把名为Foo的类型当作一个接口,你可以合并进去。例如:

    import { Draggable, LeafletEvent } from 'leaflet';
    
    interface PeanutButterEvent extends LeafletEvent {
      chunky: boolean
    }
    
    declare module 'leaflet' {
      interface Evented {
        on(type: "peanut-butter", fn: (x: PeanutButterEvent) => void): this;
      }
    }
    
    const draggable = new Draggable(new HTMLElement()) // whatever
    draggable.on("peanut-butter", e => console.log(e.chunky ? "Chunky" : "Creamy")); // ok
    draggable.on("resize", e => console.log(e.oldSize)); // still works
    

    在这里,我向名为 Eventedinterface 添加了另一个重载 on()


    另一方面,如果你想合并到classstatic类型,你可以通过添加与class同名的namespace来实现.当你写class Foo {}时,它把名为Foo的值当作一个命名空间,你可以合并进去。例如:

    import { Draggable, Evented } from 'leaflet';
    
    declare module 'leaflet' {
      namespace Evented {
        export function hello(): void;
      }
    }
    Evented.hello = () => console.log("hello"); // implement if you want
    Draggable.hello(); // okay
    Draggable.mergeOptions({}); // still works
    

    在这里,我在名为 Eventednamespace 中添加了另一个名为 hello() 的静态方法。

    Playground link to code

    【讨论】:

      猜你喜欢
      • 2021-11-30
      • 2019-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 2017-09-15
      相关资源
      最近更新 更多