打字稿:向现有抽象添加额外的重载 class
Typescript: Adding additional overloads to an existing abstract class
我正在为包 Leaflet.Editable 开发 DefinitelyTyped 的一组定义。 Leaflet 值得注意的是,它使用部分自定义的 class 实现来允许扩展纯 JavaScript、as seen here 中的现有类型。只需在代码中的任何位置调用 import 'Leaflet.Editable'
即可为现有 Leaflet class 添加新功能,例如启用和禁用某些图层的编辑功能。
它没有在 TypeScript 中实现,因此在 @types/leaflet 中实现了这种类型化,所以我正在开发的包(@types/leaflet-editable)必须导入 leaflet 命名空间并扩展现有类型。
我必须扩展现有类型而不是添加新类型,因为还有其他库(例如 react-leaflet)使用这些类型。
例如,通过扩展 MapOptions
类型(通过 merging the interfaces),我能够向 react-leaflet
的 MapComponent
组件添加新属性,因为它道具扩展 Leaflet.MapOptions
。如果我要创建一个新类型 EditableMapOptions
,它不会被 react-leaflet
扩展,因此我将无法将这些属性添加到 MapComponent
.
我能够扩展几个现有接口,并添加新接口,例如 VertexEventHandlerFn
(表示提供 VertexEvent
的事件回调)。
问题是 @types/leaflet
如何实现 map.on('click', (event: LeafletEvent) => {})
功能。这是来自 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;
...
如您所见,它使用了一个抽象 class 实现了一个通用定义,当用户包含多个由空格分隔的事件时,以及几个特定事件,当提供特定参数时,这些事件包含适当的为他们的事件处理程序打字。
我想向其中添加我的函数,但我找不到任何方法向现有抽象添加额外的重载 class。这里要注意的是,所有这些 on
的重载都是由 Leaflet 中的同一行代码实现的,因此向抽象 class 添加新方法所面临的问题(稍后将由关联的 JavaScript) 不存在于此处。
我尝试简单地尝试重新声明 abstract class Evented
以向其添加更多方法,但 TypeScript 告诉我它已经定义。我的研究只发现 TypeScript 文档指示我应该使用 mixins,我不能这样做,因为我需要修改现有的 class,创建一个新的也不能解决问题。
Here is my current TypeScript implementation of leaflet-editable so far.
从documentation for module augmentation看可能不是很清楚,但是如果你想合并到实例类型的命名class
,你可以这样做因此,通过添加与 class
同名的 interface
。当你写 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
在这里,我将 on()
的另一个重载添加到名为 Evented
的 interface
。
另一方面,如果你想合并到 class
的 static 类型,你可以通过添加到 namespace
与 class
同名。当你写 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
在这里,我将另一个名为 hello()
的静态方法添加到名为 Evented
的 namespace
。
我正在为包 Leaflet.Editable 开发 DefinitelyTyped 的一组定义。 Leaflet 值得注意的是,它使用部分自定义的 class 实现来允许扩展纯 JavaScript、as seen here 中的现有类型。只需在代码中的任何位置调用 import 'Leaflet.Editable'
即可为现有 Leaflet class 添加新功能,例如启用和禁用某些图层的编辑功能。
它没有在 TypeScript 中实现,因此在 @types/leaflet 中实现了这种类型化,所以我正在开发的包(@types/leaflet-editable)必须导入 leaflet 命名空间并扩展现有类型。
我必须扩展现有类型而不是添加新类型,因为还有其他库(例如 react-leaflet)使用这些类型。
例如,通过扩展 MapOptions
类型(通过 merging the interfaces),我能够向 react-leaflet
的 MapComponent
组件添加新属性,因为它道具扩展 Leaflet.MapOptions
。如果我要创建一个新类型 EditableMapOptions
,它不会被 react-leaflet
扩展,因此我将无法将这些属性添加到 MapComponent
.
我能够扩展几个现有接口,并添加新接口,例如 VertexEventHandlerFn
(表示提供 VertexEvent
的事件回调)。
问题是 @types/leaflet
如何实现 map.on('click', (event: LeafletEvent) => {})
功能。这是来自 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;
...
如您所见,它使用了一个抽象 class 实现了一个通用定义,当用户包含多个由空格分隔的事件时,以及几个特定事件,当提供特定参数时,这些事件包含适当的为他们的事件处理程序打字。
我想向其中添加我的函数,但我找不到任何方法向现有抽象添加额外的重载 class。这里要注意的是,所有这些 on
的重载都是由 Leaflet 中的同一行代码实现的,因此向抽象 class 添加新方法所面临的问题(稍后将由关联的 JavaScript) 不存在于此处。
我尝试简单地尝试重新声明 abstract class Evented
以向其添加更多方法,但 TypeScript 告诉我它已经定义。我的研究只发现 TypeScript 文档指示我应该使用 mixins,我不能这样做,因为我需要修改现有的 class,创建一个新的也不能解决问题。
Here is my current TypeScript implementation of leaflet-editable so far.
从documentation for module augmentation看可能不是很清楚,但是如果你想合并到实例类型的命名class
,你可以这样做因此,通过添加与 class
同名的 interface
。当你写 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
在这里,我将 on()
的另一个重载添加到名为 Evented
的 interface
。
另一方面,如果你想合并到 class
的 static 类型,你可以通过添加到 namespace
与 class
同名。当你写 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
在这里,我将另一个名为 hello()
的静态方法添加到名为 Evented
的 namespace
。