Given the following class + interface:
class Sprite implements Renderable{
constructor(){
this.on("pointerdown", this.onClick)
}
onClick(){
console.log("clicked!")
}
}
interface Renderable{
// what goes here?
}
How can I create a requirement within my interface such that all implementations of this interface must handle the event of "pointerdown"?
Does this exist in typescript?
Given the following class + interface:
class Sprite implements Renderable{
constructor(){
this.on("pointerdown", this.onClick)
}
onClick(){
console.log("clicked!")
}
}
interface Renderable{
// what goes here?
}
How can I create a requirement within my interface such that all implementations of this interface must handle the event of "pointerdown"?
Does this exist in typescript?
Share Improve this question asked Jan 21, 2021 at 0:20 Peter EdmondsPeter Edmonds 3854 silver badges16 bronze badges 1-
What is
this.on
? Is this something that you are trying to define inRenderable
? – Linda Paiste Commented Jan 22, 2021 at 21:36
2 Answers
Reset to default 3You can specify an interface for a handler, then always use that to attach the handler, but you cannot specify the interface for the event emitter itself. Either make it an interface contract (i.e. documentation, not typecheck) or separate these in two so that the implementations don't need to install the handlers themselves:
class Sprite extends Renderable {
onClick() {
console.log("clicked!")
}
}
abstract class Renderable {
constructor() {
this.on("pointerdown", this.onClick)
}
abstract onClick(): void;
}
How you define the typings for this depends on the level of specificity that you want in terms of being able to access the event variable in your callback. If you don't want to pass the event at all then obviously that's the easiest. You can use a vague type definition like Event
to access properties which are present on all events, but this will miss out on certain properties which are only present in specific event interfaces like MouseEvent
, TouchEvent
, etc. You've mentioned that you only want to handle "pointerdown"
which has the type PointerEvent
.
If you want to access e.target
, then it matters what type of element you are attaching your listener to as well.
There are various event maps for different object and elements which are built in to the DOM typings, like WindowEventMap
, and there is also a generalized GlobalEventHandlersEventMap
.
This version of an interface is the most generalized:
interface Bindable1 {
on( type: string, listener: (e: Event) => void ): void;
}
This one will infer the proper event type based on the name:
interface Bindable2 {
on<K extends keyof GlobalEventHandlersEventMap>( type: K, listener: (e: GlobalEventHandlersEventMap[K]) => void ): void;
}
This one is the most flexible as it allows you to specify a specific event map, like FileReaderEventMap
, AnimationEventMap
, etc. which might add additional specific events. But we set the default to GlobalEventHandlersEventMap
so that you don't have to specify if you don't want to.
interface Bindable3<Map = GlobalEventHandlersEventMap> {
on<K extends keyof Map>( type: K, listener: (e: Map[K]) => void ): void;
}
How can I create a requirement within my interface such that all implementations of this interface must handle the event of "pointerdown"?
I am not 100% clear on what your requirements are. Do you want your interface to contain an event handler (onClick
) which you can then attach to the "pointerdown" event? Or do you want them to declare handling for "pointerdown" specifically?
I've explained how you define this.on
, but it's also unclear to me where you implement this.on
.
Here's a simple setup that may work. We define an interface
for any object that has a property onClick
.
interface HasClickHandler {
onClick(e: MouseEvent): void;
}
You can choose where to attach the onClick
callback. Here I am attaching it to the window
. I am using (e) => obj.onClick(e)
instead of just obj.onClick
so that the this
context of the callback is the object rather than the window.
function handlePointerDown( obj: HasClickHandler ) {
window.addEventListener( "pointerdown", (e) => obj.onClick(e) );
}
This class implements the HasClickHandler
interface, so it can call handlePointerDown
with this
as the argument.
class Sprite implements HasClickHandler {
constructor() {
handlePointerDown(this);
}
onClick() {
console.log("clicked!");
}
}