[typescript] Why is Event.target not Element in Typescript?

I simply want to do this with my KeyboardEvent

var tag = evt.target.tagName.toLowerCase();

While Event.target is of type EventTarget it does not inherit from Element. So I have to cast it like this:

var tag = (<Element>evt.target).tagName.toLowerCase();

This is probably due to some browsers not following standards, right? What is the correct browser agnostic implementation in TypeScript?

PS: I am using jQuery to capture the KeyboardEvent.

This question is related to typescript

The answer is


Using typescript, I use a custom interface that only applies to my function. Example use case.

  handleChange(event: { target: HTMLInputElement; }) {
    this.setState({ value: event.target.value });
  }

In this case, the handleChange will receive an object with target field that is of type HTMLInputElement.

Later in my code I can use

<input type='text' value={this.state.value} onChange={this.handleChange} />

A cleaner approach would be to put the interface to a separate file.

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

then later use the following function definition:

  handleChange(event: HandleNameChangeInterface) {
    this.setState({ value: event.target.value });
  }

In my usecase, it's expressly defined that the only caller to handleChange is an HTML element type of input text.


JLRishe's answer is correct, so I simply use this in my event handler:

if (event.target instanceof Element) { /*...*/ }

With typescript we can leverage type aliases, like so:

type KeyboardEvent = {
  target: HTMLInputElement,
  key: string,
};
const onKeyPress = (e: KeyboardEvent) => {
  if ('Enter' === e.key) { // Enter keyboard was pressed!
    submit(e.target.value);
    e.target.value = '';
    return;
  }
  // continue handle onKeyPress input events...
};

@Bangonkali provide the right answer, but this syntax seems more readable and just nicer to me:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}

I use this:

onClick({ target }: MouseEvent) => {
    const targetDivElement: HTMLDivElement = target as HTMLDivElement;
    
    const listFullHeight: number = targetDivElement.scrollHeight;
    const listVisibleHeight: number = targetDivElement.offsetHeight;
    const listTopScroll: number = targetDivElement.scrollTop;
}

Could you create your own generic interface that extends Event. Something like this?

interface DOMEvent<T extends EventTarget> extends Event {
  target: T
}

Then you can use it like:

handleChange(event: DOMEvent<HTMLInputElement>) {
  this.setState({ value: event.target.value });
}

I'm usually facing this problem when dealing with events from an input field, like key up. But remember that the event could stem from anywhere, e.g. from a keyup listener on document, where there is no associated value. So in order to correctly provide the information I'd provide an additional type:

interface KeyboardEventOnInputField extends KeyboardEvent {
  target: HTMLInputElement;
}
...

  onKeyUp(e: KeyboardEventOnInputField) {
    const inputValue = e.target.value;
    ...
  }

If the input to the function has a type of Event, you might need to tell typescript what it actually is:

  onKeyUp(e: Event) {
    const evt = e as KeyboardEventOnInputField;
    const inputValue = evt.target.value;
    this.inputValue.next(inputValue);
  }

This is for example required in Angular.


Typescript 3.2.4

For retrieving property you must cast target to appropriate data type:

e => console.log((e.target as Element).id)