Tại sao Event.target không phải là phần tử trong Typecript?


115

Tôi chỉ muốn thực hiện điều này với KeyboardEvent của mình

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

Trong khi Event.target thuộc loại EventTarget, nó không kế thừa từ Element. Vì vậy, tôi phải cast nó như thế này:

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

Điều này có lẽ là do một số trình duyệt không tuân theo các tiêu chuẩn, phải không? Cách triển khai bất khả tri của trình duyệt trong TypeScript là gì?

Tái bút: Tôi đang sử dụng jQuery để nắm bắt được KeyboardEvent.


7
Cú pháp gọn gàng hơn một chútvar element = ev.target as HTMLElement
Adrian Moisa

Câu trả lời:


57

Nó không kế thừa từ Elementvì không phải tất cả các mục tiêu sự kiện đều là phần tử.

Từ MDN :

Phần tử, tài liệu và cửa sổ là các mục tiêu sự kiện phổ biến nhất, nhưng các đối tượng khác cũng có thể là mục tiêu sự kiện, ví dụ: XMLHttpRequest, AudioNode, AudioContext và các đối tượng khác.

Ngay cả khi KeyboardEventbạn đang cố gắng sử dụng có thể xảy ra trên một phần tử DOM hoặc trên đối tượng cửa sổ (và về mặt lý thuyết trên những thứ khác), vì vậy ngay tại đó, nó sẽ không hợp lý evt.targetkhi được định nghĩa là một Element.

Nếu đó là một sự kiện trên phần tử DOM, thì tôi sẽ nói rằng bạn có thể giả sử một cách an toàn evt.target. là một Element. Tôi không nghĩ đây là vấn đề của hành vi trên nhiều trình duyệt. Đó chỉ EventTargetlà một giao diện trừu tượng hơn Element.

Đọc thêm: https://typescript.codeplex.com/discussions/432211


8
Trong trường hợp đó, KeyboardEvent và MouseEvent phải có phần tử tương đương với EventTarget sẽ luôn chứa Phần tử liên quan. DOM thật tinh ranh ...: /
daniel.sedlacek

7
Tôi không phải là chuyên gia về DOM cũng như TypeScript nhưng tôi muốn nói rằng thiết kế của EventTarget có quá nhiều sự mơ hồ và điều đó không liên quan gì đến TypeScript.
daniel.sedlacek

2
@ daniel.sedlacek Mặt khác, KeyboardEvents có thể xảy ra trên cả phần tử DOM và trên đối tượng window (và về mặt lý thuyết là những thứ khác), do đó, không thể đưa ra KeyboardEvent.targetmột kiểu cụ thể hơn EventTarget, trừ khi bạn nghĩ KeyboardEventcũng phải là loại chung KeyboardEvent<T extends EventTarget>và muốn buộc phải đặt KeyboardEvent<Element>tất cả trong mã của bạn. Tại thời điểm đó, tốt hơn hết bạn nên bó bột rõ ràng, mặc dù có thể sẽ rất đau.
JLRishe

14
Trong trường hợp nó hữu ích cho bất kỳ ai khác trong tương lai, tôi cần truyền dưới dạng một loại phần tử cụ thể để truy cập thuộc valuetính của <select>thẻ. ví dụlet target = <HTMLSelectElement> evt.target;
munsellj

1
@munsellj (thật không may) đó là cách chính xác để xử lý sự không rõ ràng trong môi trường đã nhập.
pilau

47

Sử dụng bản đánh chữ, tôi sử dụng giao diện tùy chỉnh chỉ áp dụng cho chức năng của tôi. Ví dụ trường hợp sử dụng.

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

Trong trường hợp này, handleChange sẽ nhận một đối tượng có trường đích thuộc loại HTMLInputElement.

Sau này trong mã của tôi, tôi có thể sử dụng

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

Một cách tiếp cận rõ ràng hơn sẽ là đặt giao diện vào một tệp riêng biệt.

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

sau đó sử dụng định nghĩa hàm sau:

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

Trong usecase của tôi, nó được định nghĩa rõ ràng rằng người gọi duy nhất để xử lý handleChange là một loại phần tử HTML của văn bản đầu vào.


Điều này làm việc một cách hoàn hảo đối với tôi - Tôi đã cố gắng tất cả các loại nastiness, mở rộng EventTarget vv nhưng đây là giải pháp sạch 1
Kitson

1
Chỉ cần thêm vào đó, nếu bạn cần để mở rộng định nghĩa sự kiện bạn có thể làm một cái gì đó như thế này:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Kitson

40

Câu trả lời của JLRishe là đúng, vì vậy tôi chỉ cần sử dụng câu này trong trình xử lý sự kiện của mình:

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

28

Bản đánh giá 3.2.4

Để truy xuất thuộc tính, bạn phải truyền đích đến kiểu dữ liệu thích hợp:

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

Có giống với <HTMLInputElement>event.target;cú pháp không?
Konrad Viltersten

@KonradViltersten, họ cũng làm điều tương tự. Các ascú pháp đã được giới thiệu vì nó mâu thuẫn với JSX. Nó được khuyến khích sử dụng ascho nhất quán. basarat.gitbooks.io/typescript/docs/types/type-assertion.html
Adam

Aha, tôi hiểu rồi. Nó cũng xuất hiện thêm C # 'ish, trong nhiều trường hợp là một lợi thế, tùy thuộc vào kinh nghiệm phụ trợ của nhóm. Miễn là nó không phải là một trong những người bạn sai mà cú pháp giống một cái gì đó nhưng ngụ ý một cái gì đó hoàn toàn khác về mặt kỹ thuật. (Tôi đang nghĩ varconst giữa Angular và C #, một trải nghiệm đáng buồn của tôi, hehe).
Konrad Viltersten

2

Bạn có thể tạo giao diện chung của riêng mình mở rộng Event. Một cái gì đó như thế này?

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

Sau đó, bạn có thể sử dụng nó như:

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

1

Với typecript, chúng ta có thể tận dụng các bí danh kiểu, như sau:

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

0

@Bangonkali cung cấp câu trả lời đúng, nhưng cú pháp này có vẻ dễ đọc hơn và đẹp hơn đối với tôi:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.