Typescript: Request to change currentTarget in Event interface for lib.d.ts

Created on 29 Jul 2014  ·  36Comments  ·  Source: microsoft/TypeScript

When using the Event interface from lib.d.ts, and attaching a listener, the callback will get an object of type Event. However, the Event's currentTarget property is of type EventTarget (whereas it's should be of type Element/HTMLElement).

lib.d.ts Suggestion help wanted

Most helpful comment

I ran into this TS2339: Property 'result' does not exist on type 'EventTarget' in JS FileReader onload, and another warning for getSummary() on the event passed to FileReader's onerror.

My work-around, to suppress the horrid red squiggily lines;-) is the following:

interface FileReaderEventTarget extends EventTarget {
    result:string
}

interface FileReaderEvent extends Event {
    target: FileReaderEventTarget;
    getMessage():string;
}

Then in my app:

reader.onload = function(fre:FileReaderEvent) {
        var data = JSON.parse(fre.target.result);
        ...
    }

The generated JS codes looks good and works for me. Could this kind of solution, for unusual JS event types, be added to lib.d.ts?

I'm guessing my solution is overly simplistic. But it would help to know why.

All 36 comments

XMLHttpRequest object also can be currentTarget but it is not Element/HTMLElement. Maybe that's the reason behind this. Would generic type improve this?

interface Event<T extends EventTarget> {
    /* ... */
    currentTarget: T;
    /* ... */
}

interface EventListener<T extends EventTarget> {
    (evt: Event<T>): void;
}

interface HTMLElement {
    /* ... */
    addEventListener(type: string, listener: EventListener<HTMLElement>, useCapture?: boolean): void;
}

Looks like it'll go a long way to improving it.

Sent from my iPhone

On 3 Aug 2014, at 13:34, SaschaNaz [email protected] wrote:

XMLHttpRequest object also can be currentTarget but it is not Element/HTMLElement. Maybe that's the reason behind this. Would generic type improve this?

interface Event {
/* ... _/
currentTarget: T;
/_ ... */
}

interface EventListener {
(evt: Event): void;
}

interface HTMLElement {
/* ... */
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void;
}

Reply to this email directly or view it on GitHub.

Note that not every event target is an Element (http://www.w3.org/TR/DOM-Level-3-Events/#event-types), so the solution here would have to be more along the lines of @SaschaNaz's suggestion.

The problem is that we currently generate lib.d.ts, using a script, based on a file which we can't make public at this time, and that file is being deprecated in favor of a new one. Because of that, we're not going to make improvements in the script at this time, but hopefully in the future we can take PRs on the lib.d.ts generation script/input.

Tagging 'Revisit' for now - please ping us on this in a month and I can see where we're at.

Is there any syntax to refer the current type? I think this can be solved more easily if we can do this kind of work:

interface HTMLElement {
    addEventListener(type: string, listener: EventListener<this>, useCapture?: boolean): void;
}

var image: HTMLImageElement;
var video: HTMLVideoElement;
image.addEventListener // receives EventListener<HTMLImageElement> type
video.addEventListener // receives EventListener<HTMLVideoElement> type

That functionality does not exist, it's something akin to what's suggested in #285 and #229

Hi all, pinging this thread. I ran into this issue with Event.target. I would imagine most of the time a target is an HTMLElement. It is a little odd that the default type assumes it isn't. I tried @SaschaNaz's suggestion and ran into the "duplicate identifier" issue (sorry I may be missing something, I'm pretty new to TypeScript).

Edit: this worked to quiet the warnings: (<HTMLElement>event.target).tagName

@rayshan the suggestion was for what should go into the lib.d.ts file and the file is auto generated based directly on the implementation of Internet Explorer. So the error you encountered is accurate. Right now the only way around it is to build without the built in lib (--noLib) and use the workaround, or do what you have done, which is cast the target. There are currently a number of challenges of dealing with the return types of the DOM right now in TypeScript (mostly because the DOM isn't the most consistent/structured/type safe/consistently implemented set of APIs).

Now that #4910 is merged, can this be revisited?

@zhengbli might have some context on the status of lib.d.ts issues that require script based generation

PRs welcomed. here is some infromation on contributing lib.d.ts changes: https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md#contributing-libdts-fixes

I ran into this TS2339: Property 'result' does not exist on type 'EventTarget' in JS FileReader onload, and another warning for getSummary() on the event passed to FileReader's onerror.

My work-around, to suppress the horrid red squiggily lines;-) is the following:

interface FileReaderEventTarget extends EventTarget {
    result:string
}

interface FileReaderEvent extends Event {
    target: FileReaderEventTarget;
    getMessage():string;
}

Then in my app:

reader.onload = function(fre:FileReaderEvent) {
        var data = JSON.parse(fre.target.result);
        ...
    }

The generated JS codes looks good and works for me. Could this kind of solution, for unusual JS event types, be added to lib.d.ts?

I'm guessing my solution is overly simplistic. But it would help to know why.

I would love to fix this issue. But as I see the only reference to currentTarget is inside generated webworker.generated.d.ts files in TSJS generator. I have no idea how to fix this 😞
I really hope somebody could fix this nearly 3 years old issue. Such errors may be the reason why I often hear people say that TypeScript is hard to use and that really makes me sad.

Well. I tried to start solve this issue. I create a PR https://github.com/Microsoft/TSJS-lib-generator/pull/202
Hopefully this is going into the right direction.

I'm getting Property 'getBoundingClientRect' does not exist on type 'EventTarget'.. I think this is a good idea.

Well, the PR is pending since nearly 2 month. I'll look into this if there is anything that could be done to speed this up.

It would be really great if we could have currentTarget be generic, so that for example HTMLInputElement.onchange can be of type (event: Event<HTMLInputElement>) => void so that event.currentTarget.value works without any cast or type annotations. The typings for React do this, but dom.lib.d.ts unfortunately not.

This is blocked by performance issue caused by generics as introducing generics doubles memory usage 😭

Do these performance problems apply equally to the React typings?

lib.d.ts doesn't include React typings but you can test it by adding --diagnostics to the command.

@felixfbecker I personally doubt that this will be fixed soon. I guess most people already created their workaround or abandoned TypeScript. That's also why there are so few people hitting this problem.

This issue still exists in Version 1.18.0 (1.18.0)

Hello,

Same issue with ... and i guess it's not fixed yet.

when i flag my angular 4 project for production, then the issue appear, else, while im using just ng serve .. this works fine. So i guess there's something related to how angular manage production files.

Hope some progress on this issue. It is hard to manipulate dom with Typescript.

This issue is four years old and the corresponding PR nearly one year I doubt this will be fixed any time soon.

This issue has been around for 4 years but has not been fixed yet.

There is a fix available in https://github.com/Microsoft/TSJS-lib-generator/pull/207
But @saschanaz is blocking based on the performance.

Casting party tonite at 11 - unload your browser tabs:
confirmationMessage(event: BeforeUnloadEvent): any {
const activeElement: HTMLElement = <HTMLElement>(<Document>event.target).activeElement;

:dancing_men:

What about adding

    readonly currentTarget: Element | null;
    readonly target: Element | null;

on UIEvent only? This is not very specific, but makes most code happy.
Perhaps even without | null as on a UIEvent both are always set

same issue here. I was trying to use Vue with Typescript and wanted to get the value of an input field as the user typed. But event.target.value would not pass the type checker even though - i think - a text inout must always produce such fields for such an event

We got rid of the error by adding type any to our code:

this.url = (<any>event).target.result;

What about typing Event and EventTarget?

interface Event<C = any, S = any, T = any> {
  ...
  currentTarget: EventTarget<C> | null;
  srcElement: EventTarget<S> | null;
  target: EventTarget<T> | null;
  ...
}

interface EventTarget<T = any> {
  ...
}

I encountered this issue while using the FileReader, a simple cast to the correct type fixes it

const fileReader = new FileReader();
fileReader.onload = $ev => {
  console.log($ev); // type ProgressEvent
  console.log($ev.target); // type FileReader
  // console.log($ev.target.result); // editor and autocomplete doesn't show any error
  console.log(($ev.target as FileReader).result); // casting compiles fine
};
fileReader.readAsText(file);

Are there any updates about this topic? It would be useful to have it without force casting event.target every time or any-casting event (as @gautamkrishnar did above) . Also this is open since 2014. Thank you!

Indeed, would be nice with some kind of official response to this issue before its 6th birthday

Yep, this is probably the Number 1 day-long nuisance when working with DOM, JSX, etc.

In fact, it's the only daily nuisance I have - and I imagine a million people have this, all day long.

It's really difficult to understand why this doesn't get any priority.

Same for event.target. A very common scenario is adding a click handler to a parent element when children don't exist yet, and when there will be many children. A simple test for event.target.tagName or even classList is a common thing I do. It works....have used it for many years. I don't get intellisense for tagName/classList since EventTarget is not classified as HTMLElement, but it works.

Was this page helpful?
0 / 5 - 0 ratings