ChatGPT解决这个技术问题 Extra ChatGPT

Property 'value' does not exist on type 'EventTarget'

I am using TypeScript Version 2 for an Angular 2 component code.

I am getting error "Property 'value' does not exist on type 'EventTarget'" for below code, what could be the solution. Thanks!

e.target.value.match(/\S+/g) || []).length

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'text-editor',
  template: `
    <textarea (keyup)="emitWordCount($event)"></textarea>
  `
})
export class TextEditorComponent {
  @Output() countUpdate = new EventEmitter<number>();

  emitWordCount(e: Event) {
    this.countUpdate.emit(
            (e.target.value.match(/\S+/g) || []).length);
  }
}
tektutorialshub.com/angular/… I think this will answer the question

s
smnbbrv

You need to explicitly tell TypeScript the type of the HTMLElement which is your target.

The way to do it is using a generic type to cast it to a proper type:

this.countUpdate.emit((<HTMLTextAreaElement>e.target).value./*...*/)

or (as you like)

this.countUpdate.emit((e.target as HTMLTextAreaElement).value./*...*/)

or (again, matter of preference)

const target = e.target as HTMLTextAreaElement;

this.countUpdate.emit(target.value./*...*/)

This will let TypeScript know that the element is a textarea and it will know of the value property.

The same could be done with any kind of HTML element, whenever you give TypeScript a bit more information about their types it pays you back with proper hints and of course less errors.

To make it easier for the future you might want to directly define an event with the type of its target:

// create a new type HTMLElementEvent that has a target of type you pass
// type T must be a HTMLElement (e.g. HTMLTextAreaElement extends HTMLElement)
type HTMLElementEvent<T extends HTMLElement> = Event & {
  target: T; 
  // probably you might want to add the currentTarget as well
  // currentTarget: T;
}

// use it instead of Event
let e: HTMLElementEvent<HTMLTextAreaElement>;

console.log(e.target.value);

// or in the context of the given example
emitWordCount(e: HTMLElementEvent<HTMLTextAreaElement>) {
  this.countUpdate.emit(e.target.value);
}

@smnbbrv my case is an img file location then display the img, based on SO Template: <img [src]="url"> <br/> <input type='file' (change)="showImg($event)"> Component: ... this.url = event.target.result; Sometime works sometimes doesn't, when it's not err is error TS2339: Property 'result' does not exist on type 'EventTarget' As you suggested tell TS more about it, in the place HTMLTextAreaElement I tried HTMLInputElement then target.value no more err but image not displaying.
I was surprised to see that you couldn't pass a type into the Event type. You should really be able to use Event<HTMLInputElement> as a type.
@RoRo event has following similar properties: target, currentTarget and srcElement; one would need to type 3 generic types; even if they use default types e.g. Event<T = any, C = any, S = any> for the mentioned above it could be more uncomfortable to use than the simple as statement. I could also imagine a potential holywar for what should be first generic: target or currentTarget. Additionally, many libraries abuse HTML event and can potentially put anything they want in the mentioned properties. Probably these are the reasons why they did not do it as built-in generics
For my ion-searchbar, I am using (ionChangeEvent.target as HTMLIonInputElement).value as string
Why does it need to be explicit? This is such a waste of time, DOM events are one of the biggest drawbacks of using TS for me, I'm always looking for TS definitions on SO.
T
Torsten Barthel

Here is the simple approach I used:

const element = event.currentTarget as HTMLInputElement
const value = element.value

The error shown by TypeScript compiler is gone and the code works.


if you are using checkboxes too this is a good solution: const value = e.currentTarget.type === 'checkbox' ? (e.currentTarget as HTMLInputElement).checked : e.currentTarget.value
b
belvederef

Since I reached two questions searching for my problem in a slightly different way, I am replicating my answer in case you end up here.

In the called function, you can define your type with:

emitWordCount(event: { target: HTMLInputElement }) {
  this.countUpdate.emit(event.target.value);
}

This assumes you are only interested in the target property, which is the most common case. If you need to access the other properties of event, a more comprehensive solution involves using the & type intersection operator:

event: Event & { target: HTMLInputElement }

You can also go more specific and instead of using HTMLInputElement you can use e.g. HTMLTextAreaElement for textareas.


B
BuZZ-dEE

Angular 10+

Open tsconfig.json and disable strictDomEventTypes.

  "angularCompilerOptions": {
    ....
    ........
    "strictDomEventTypes": false
  }

Disabling strict rules can allow for improper code to be written, this isn't very good advice, especially with the advancements of Angular 10+.
Neither is having to cast type explicitly I am afraid, especially in such a small/local scope. It gives the appearance of some type safety, but is really only as good/bad as disabling the strict check.
This method works for me. Casting is not working in the html. This does not work (keyup)="doFilter(($event.target as HTMLTextAreaElement).value)"
@cklimowski - for me this is the only way I could do in order to make the application running in angular old version in the latest version.
C
C. Lewis

In my case, I had:

const handleOnChange = (e: ChangeEvent) => {
  doSomething(e.target.value);
}

And the issue was that I did not provide a type argument to ChangeEvent so that it knows e.target was an HTMLInputElement. Even if I manually told it that target was an input element (e.g. const target: HTMLInputElement = e.target), the ChangeEvent still didn't know that made sense.

The solution was to do:

// add type argument
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
  doSomething(e.target.value);
}

Ahh so many times I've done this and come back to this answer. Finally upvoting
Where is ChangeEvent imported from?
A
Ali Maher

consider $any()

<textarea (keyup)="emitWordCount($any($event))"></textarea>

All this solution not apply in angular 10+,So please specify angular version.
@Rahi.Shah I tried it on Angular 12 and it worked. If you are trying to access a nested property, you need to wrap the object around the propety, e.g. $any($event.target).value, this will mark the event.target property as any and you can access the value for example.
@Rahi.Shah I did use this in angular 12, but this solution stackoverflow.com/a/68106554/11135174 is way cleaner, since you still use the capabilities of Typescript without any "dirty fix".
Works for me in angular 13. $any($event.target).checked
J
James D

For those who are getting this error in angular 13, since upgrading from a previous version

The issue for me was I was using the following in my HTML (which was allowed before)

(keyup)="applyFilter($event.target.value)" 

The fix for this was:

HTML:

(keyup)="applyFilter($event)"

Component - in my called function:

applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    // ... etc....
}

And now I could use filterValue again as before, to filter my values in my page


As Angular becomes heavier on typing this is the answer to this entire thread. All other answers are N/A. Send the Event work with typings, target and values in your controller.
B
Burak Odabaş

Here is another simple approach, I used;

    inputChange(event: KeyboardEvent) {      
    const target = event.target as HTMLTextAreaElement;
    var activeInput = target.id;
    }

P
Pang
fromEvent<KeyboardEvent>(document.querySelector('#searcha') as HTMLInputElement , 'keyup')
    .pipe(
      debounceTime(500),
      distinctUntilChanged(),
      map(e  => {
            return e.target['value']; // <-- target does not exist on {}
        })
    ).subscribe(k => console.log(k));

Maybe something like the above could help. Change it based on the real code. The issue is ........ target['value']


P
ParisaN

Angular 11+

Open tsconfig.json and disable strictTemplates.

 "angularCompilerOptions": {
    ....
    ........
    "strictTemplates": false
  }

Worked Angular 11
This could bring so, so many bugs. Don't do this. At least, if you are on a hurry, use "strictDomEventTypes": false instead, in tsconfig.json
S
Steven Liekens

Don't use the workarounds from other answers that involve casting the event, the event target or entirely disabling type checking. It is not safe.

Instead you should "pluck" the value from the HTML element and pass that as an argument instead.

Oversimplified example:

<input #searchBox type="text" (input)="doSearch(searchBox.value)">
doSearch(text: string): void {
}

So if you expand that to the original example, you should get this:

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'text-editor',
  template: `
    <textarea #text (keyup)="emitWordCount(text.value)"></textarea>
  `
})
export class TextEditorComponent {
  @Output() countUpdate = new EventEmitter<number>();

  emitWordCount(text: string) {
    this.countUpdate.emit(
      (text.match(/\S+/g) || []).length);
  }
}

Could you elaborate why this isn't "safe" ?
@RaphaëlBalet because casting is effectively telling the TypeScript compiler "don't do strict type checking on this line of code". A cast object only has programmer type checking, and brains are unreliable. My proposed solution does not rely on casting or dynamic typing.
Excellent solution
This seems to be the now-recommended way from Angular: angular.io/guide/…
I
Idriss Sakhi

Best way is to use templating => add id to your input and then use it value

searchNotary(value: string) {
 // your logic
}

this way you will never have Typescript error when strict verification is activated => See angular Docs


M
Monfa.red

User TypeScript built in utility type Partial<Type>

In your template

(keyup)="emitWordCount($event.target)"

In your component

 emitWordCount(target: Partial<HTMLTextAreaElement>) {
    this.countUpdate.emit(target.value./*...*/);
  }

Thx a lot, working like a charm. For Angular users, use this and do not forget to enable "strictDomEventTypes": true. Also working with Partial<HTMLInputElement> for inputs
m
micronyks

I believe it must work but any ways I'm not able to identify. Other approach can be,

<textarea (keyup)="emitWordCount(myModel)" [(ngModel)]="myModel"></textarea>


export class TextEditorComponent {
   @Output() countUpdate = new EventEmitter<number>();

   emitWordCount(model) {
       this.countUpdate.emit(
         (model.match(/\S+/g) || []).length);
       }
}

q
qiAlex

Here is one more way to specify event.target:

import { Component, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'text-editor', template: `` }) export class TextEditorComponent { @Output() countUpdate = new EventEmitter(); emitWordCount({ target = {} as HTMLTextAreaElement }) { // <- right there this.countUpdate.emit( // using it directly without `event` (target.value.match(/\S+/g) || []).length); } }


C
Charles Zhao

Use currentValue instead, as the type of currentValue is EventTarget & HTMLInputElement.