"属性'value'在类型'EventTarget'上不存在。"

418

我正在使用TypeScript 2版本编写Angular 2组件代码。

在下面的代码中,我收到了“属性'value'不存在于类型'EventTarget'上”的错误,有什么解决方法?谢谢!

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);
  }
}

这个回答解决了你的问题吗?属性'value'在类型'HTMLElement'的值上不存在 - miken32
2
https://www.tektutorialshub.com/angular/property-value-does-not-exist-on-type-eventtarget-error-in-angular/我认为这将回答这个问题。 - ColdFire
19个回答

489

您需要明确告诉TypeScript您的目标是哪种HTMLElement类型。

做法是使用通用类型将其转换为正确的类型:

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

或者(随你喜欢)
this.countUpdate.emit((e.target as HTMLTextAreaElement).value./*...*/)

或者(再次强调,这是个人偏好)。
const target = e.target as HTMLTextAreaElement;

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

这将让TypeScript知道该元素是一个textarea,并且它会了解到value属性。
对于任何类型的HTML元素,只要您向TypeScript提供有关其类型的更多信息,它就会用正确的提示回报您,当然还有更少的错误。
为了使未来更容易,您可能希望直接定义具有其目标类型的事件:
// 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);
}

1
@smnbbrv 我的情况是一个img文件位置,然后根据SO显示图片。 模板:<img [src]="url"> <br/> <input type='file' (change)="showImg($event)"> 组件:... this.url = event.target.result; 有时候可以工作,有时候不行,当它不行时,错误是 error TS2339: Property 'result' does not exist on type 'EventTarget' 正如你所建议的那样,告诉TS更多关于它的信息,在HTMLTextAreaElement的位置上,我尝试了HTMLInputElement然后是target.value没有更多的错误,但是图片没有显示。 - Jeb50
我很惊讶地发现你不能将类型传递到“Event”类型中。 你真的应该能够使用“Event<HTMLInputElement>”作为一种类型。 - RonanCodes
11
为什么需要明确表达?这太浪费时间了,DOM事件是我使用TS时最大的缺点之一,我总是在Stack Overflow上寻找TS定义。 - Vadorequest
@Vadorequest 这个问题很简单:无法将其隐式化。有一个事件类型,你永远不知道事件的来源,只能在运行时知道。在这里,你实际上是在说“我相信这个目标是HTMLTextAreaElement”。TypeScript编译器无法从任何地方提取此信息。 - smnbbrv
@LeonardoRick 请尝试将类型 HTMLElementEvent<T extends HTMLElement> = Event & { 更改为 type HTMLElementEvent<T extends HTMLElement> = MouseEvent & {(MouseEvent) - smnbbrv
显示剩余6条评论

108

这里是我使用的简单方法:

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

TypeScript编译器显示的错误已经消失,代码可以正常工作。


2
如果您也在使用复选框,这是一个不错的解决方案: const value = e.currentTarget.type === 'checkbox' ? (e.currentTarget as HTMLInputElement).checked : e.currentTarget.value - td18

82

对于那些在从旧版本升级到Angular 13后遇到此错误的人

对我来说,问题是我在我的HTML中使用了以下内容(之前是允许的)

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

解决方法是:

HTML:

(keyup)="applyFilter($event)"

组件 - 在我的调用函数中:

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

现在我可以像以前一样再次使用filterValue。


5
随着Angular变得更加注重类型,这就是整个线程的答案。所有其他答案都不适用。在您的控制器中发送具有类型、目标和值的 Event 工作即可。 - Ben Racicot
太棒了,这就是需要的答案。 - java-addict301
我有 (change)="someVar = $event.target.value",所以我不想在我的组件中再创建另一个监听器。这是明确的页面元素,因此应该可以推断出事件类型。它像这样无缝运行,但我不喜欢有类型错误。有什么内联解决方案的建议吗? - ThaJay
@ThaJay,你使用(change)而不是组件和HTML字段之间的单向或双向绑定有什么原因吗? - James D
@JamesD 我不知道,对 Angular 还不是很熟悉。在这种情况下,使用绑定会更好吗? - ThaJay
显示剩余2条评论

39

在我的情况下,我有:

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

问题在于我没有向ChangeEvent提供类型参数,以便它知道e.target是一个HTMLInputElement。即使我手动告诉它target是一个输入元素(例如const target: HTMLInputElement = e.target),ChangeEvent仍然不知道这是有意义的。

解决方法是:

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

1
啊,我已经做了这么多次并回到了这个答案。终于点赞了。 - Mote Zart
1
ChangeEvent 是从哪里导入的? - Chris Fremgen
@ChrisFremgen 这是从React导入的。 - Operator
2
问题是关于Angular的,不是React。 - java-addict301

35

由于我用稍微不同的方式搜索了两个问题,因此在这里复制我的答案以防你最终到达这里。

在所调用的函数中,您可以使用以下内容定义自己的类型:

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

假设您只对target属性感兴趣,这是最常见的情况。如果您需要访问event的其他属性,则更全面的解决方案涉及使用&类型交集运算符:

event: Event & { target: HTMLInputElement }

您还可以更加具体,而不是使用HTMLInputElement,您可以使用例如HTMLTextAreaElement用于文本区域。


34

Angular 10+

打开tsconfig.json并禁用strictDomEventTypes

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

27
禁用严格规则可能会导致编写不当的代码,这并不是很好的建议,特别是随着Angular 10+的发展。 - cklimowski
10
在这种小范围内,我并不担心需要显式地进行类型转换。虽然它看起来有一些类型安全性,但实际上只是像禁用严格检查一样好或坏。 - Xinchao
3
这种方法对我很有效。在HTML中无法使用Casting。这段代码不起作用:(keyup)="doFilter(($event.target as HTMLTextAreaElement).value)" - Paul John Leonard
@cklimowski - 对我来说,这是唯一的方法,可以使应用程序在最新版本的Angular中运行旧版本。 - aj go
1
这是正确的答案。如果 Angular 不知道类型,那么它应该保持沉默,或者最多只能限制自己显示警告。进行强制转换只会以同样的方式覆盖错误,但会给人一种虚假的安全感。 - m12lrpv

24
不要使用其他答案中涉及强制转换事件、事件目标或完全禁用类型检查的解决方法,这样做不安全。 相反,您应该从HTML元素中“pluck”出该值,并将其作为参数传递。 过于简化的示例:
<input #searchBox type="text" (input)="doSearch(searchBox.value)">
doSearch(text: string): void {
}

所以,如果你将其扩展到原始示例,应该会得到这个:

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);
  }
}

你能详细说明为什么这不是“安全”的吗? - Raphaël Balet
6
由于casting的本质是告诉TypeScript编译器“在这行代码上不做严格的类型检查”,因此,cast对象仅具有程序员类型检查,而人的大脑是不可靠的。我的解决方案不依赖于casting或动态类型。@RaphaëlBalet - Steven Liekens
3
优秀的解决方案 - atwright147
3
这似乎是Angular现在推荐的方式:https://angular.io/guide/user-input#get-user-input-from-a-template-reference-variable - waternova
1
@ThaJay 这不是类型错误,它实际上可以是一个字符串,你需要编写代码将其转换为数字。更好的做法是使用 numberInput.valueAsNumber - Steven Liekens
显示剩余3条评论

21

考虑任何东西 $any()

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

1
所有这些解决方案都不适用于 Angular 10+,请指定 Angular 版本。 - Rahi.Shah
6
我在 Angular 12 上尝试了它,它有效。如果你试图访问一个嵌套的属性,你需要将对象包裹在属性周围,例如 $any($event.target).value,这将把 event.target 属性标记为 any,因此你可以访问其值。 - Shirohige
@Rahi.Shah 我确实在 Angular 12 中使用了这个,但是这个解决方案 https://dev59.com/UlgQ5IYBdhLWcg3w43-V#68106554 更加简洁,因为你仍然可以使用 TypeScript 的能力而不需要任何“脏修复”。 - Raphaël Balet
在 Angular 13 中对我有效。$any($event.target).checked - Franklin'j Gil'z

13

这里是我采用的另一种简单方法:

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

8
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));

也许像上面这样的代码可以帮助解决问题。根据实际代码进行更改。问题出在目标['value']上。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接