I am working on developing a set of definitions for DefinitelyTyped, for the package Leaflet.Editable. Leaflet is notable in that it uses a partially custom class implementation to allow for extending of existing types in pure JavaScript, as seen here. Simply calling import 'Leaflet.Editable' anywhere in your code will add new functionality to the existing Leaflet classes, such as the ability to enable and disable editing of certain layers.
It is not implemented in TypeScript, and as such typing is implemented in @types/leaflet, so the package I am developing (@types/leaflet-editable) has to import the leaflet namespace and extend the existing types.
I must extend the existing types rather than adding new ones because there are other libraries (such as react-leaflet) that use those types.
For example, by extending the MapOptions type (by merging the interfaces), I was able to add new properties to react-leaflet's MapComponent component, since its props extend Leaflet.MapOptions. If I were to create a new type, EditableMapOptions, it would not be extended by react-leaflet and thus I would not be able to add those properties to MapComponent.
I was able to extend several existing interfaces, and add new ones such as VertexEventHandlerFn (which represents an event callback that provides a VertexEvent).
The issue is how @types/leaflet implements the map.on('click', (event: LeafletEvent) => {}) function. Here's a snippet from the DefinitelyTyped repo:
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;
...
As you can see, it uses an abstract class that implements a generic definition for when users include multiple events separated by spaces, as well as several specific events that, when specific arguments are provided, include proper typing for their event handlers.
I wanted to add my functions to this, but I cannot find any means to add additional overloads to an existing abstract class. The thing to note here is that all these overloads of on are implemented by the same line of code in Leaflet, so the issues faced by adding new methods to an abstract class (that would later go unimplemented by the associated JavaScript) do not exist here.
I tried simply attempting to redeclare abstract class Evented to add more methods to it but TypeScript tells me it's already defined. My research only found the TypeScript documentation indicating that I should utilize mixins, which I cannot do because I need to modify the existing class, and creating a new one would not solve the problem.
Here is my current TypeScript implementation of leaflet-editable so far.