Mengapa Event.target bukan Elemen di Typecript?


115

Saya hanya ingin melakukan ini dengan KeyboardEvent saya

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

Meskipun Event.target berjenis EventTarget, Event.target tidak mewarisi dari Element. Jadi saya harus melakukan cast seperti ini:

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

Ini mungkin karena beberapa browser tidak mengikuti standar, bukan? Apa implementasi agnostik browser yang benar di TypeScript?

PS: Saya menggunakan jQuery untuk merekam KeyboardEvent.


7
Sintaks yang sedikit lebih bersihvar element = ev.target as HTMLElement
Adrian Moisa

Jawaban:


57

Itu tidak diturunkan dari Elementkarena tidak semua target acara adalah elemen.

Dari MDN :

Elemen, dokumen, dan jendela adalah target acara yang paling umum, tetapi objek lain juga bisa menjadi target acara, misalnya XMLHttpRequest, AudioNode, AudioContext, dan lainnya.

Bahkan yang KeyboardEventAnda coba gunakan dapat terjadi pada elemen DOM atau pada objek jendela (dan secara teoritis pada hal-hal lain), jadi saat ini tidak masuk akal untuk evt.targetdidefinisikan sebagai file Element.

Jika ini adalah peristiwa pada elemen DOM, maka saya akan mengatakan bahwa Anda dapat berasumsi dengan aman evt.target. adalah sebuah Element. Saya tidak berpikir ini adalah masalah perilaku lintas-browser. Hanya itu EventTargetadalah antarmuka yang lebih abstrak daripada Element.

Bacaan lebih lanjut: https://typescript.codeplex.com/discussions/432211


8
Dalam hal ini, KeyboardEvent dan MouseEvent harus memiliki yang setara dengan EventTarget itu sendiri yang akan selalu berisi Elemen terkait. DOM sangat cerdik ...: /
daniel.sedlacek

7
Saya bukan ahli DOM atau TypeScript tetapi saya akan mengatakan desain EventTarget memiliki terlalu banyak ambiguitas dan itu tidak ada hubungannya dengan TypeScript.
daniel.sedlacek

2
@ daniel.sedlacek Di sisi lain, KeyboardEvents dapat terjadi pada kedua elemen DOM dan pada objek jendela (dan secara teoritis hal-hal lain), jadi saat ini tidak mungkin untuk memberikan KeyboardEvent.targettipe yang lebih spesifik dari EventTarget, kecuali jika menurut Anda KeyboardEventjuga harus menjadi tipe generik KeyboardEvent<T extends EventTarget>dan ingin dipaksa untuk memasukkan KeyboardEvent<Element>semua kode Anda. Pada titik itu, Anda lebih baik hanya melakukan pemeran eksplisit, meskipun mungkin menyakitkan.
JLRishe

14
Jika itu berguna bagi orang lain di masa mendatang, saya perlu melakukan transmisi sebagai jenis elemen tertentu untuk mengakses valueproperti <select>tag. misalnyalet target = <HTMLSelectElement> evt.target;
munsellj

1
@munsellj (sayangnya) itu adalah cara yang benar untuk menangani ambiguitas dalam lingkungan yang diketik.
pilau

47

Menggunakan skrip ketikan, saya menggunakan antarmuka khusus yang hanya berlaku untuk fungsi saya. Contoh kasus penggunaan.

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

Dalam hal ini, handleChange akan menerima objek dengan bidang target berjenis HTMLInputElement.

Nanti di kode saya bisa saya gunakan

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

Pendekatan yang lebih bersih adalah meletakkan antarmuka ke file terpisah.

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

kemudian gunakan definisi fungsi berikut:

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

Dalam usecase saya, secara tegas didefinisikan bahwa satu-satunya pemanggil untuk handleChange adalah tipe elemen HTML dari teks input.


Ini bekerja dengan sempurna untuk saya - Saya mencoba segala macam keburukan, memperpanjang EventTarget dll. Tetapi ini adalah solusi terbersih +1
Kitson

1
Sebagai tambahan, jika Anda perlu memperluas definisi acara, Anda dapat melakukan sesuatu seperti ini:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Kitson

40

Jawaban JLRishe benar, jadi saya cukup menggunakan ini di event handler saya:

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

28

Ketikan 3.2.4

Untuk mengambil properti, Anda harus mentransmisikan target ke tipe data yang sesuai:

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

Apakah itu sama dengan <HTMLInputElement>event.target;sintaksnya?
Konrad Viltersten

@KonradVersten, mereka melakukan hal yang sama. The assintaks diperkenalkan karena bertentangan dengan BEJ. Dianjurkan untuk digunakan asuntuk konsistensi. basarat.gitbooks.io/typescript/docs/types/type-assertion.html
Adam

Aha, begitu. Ini juga tampak lebih C # 'yang dalam banyak kasus merupakan keuntungan, tergantung pada pengalaman backend tim. Selama itu bukan salah satu teman palsu yang sintaksnya menyerupai sesuatu tetapi menyiratkan sesuatu yang sama sekali berbeda secara teknis. (Saya pikir var dan const antara Angular dan C #, pengalaman menyedihkan saya, hehe).
Konrad Viltersten

2

Bisakah Anda membuat antarmuka umum Anda sendiri yang meluas Event. Sesuatu seperti ini?

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

Kemudian Anda bisa menggunakannya seperti:

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

1

Dengan skrip ketikan kita dapat memanfaatkan alias tipe, seperti:

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 memberikan jawaban yang benar, tetapi sintaks ini tampaknya lebih mudah dibaca dan lebih baik bagi saya:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.