TypeScript: casting HTMLElement


197

Apakah ada yang tahu cara melakukan casting di TypeScript?

Saya mencoba melakukan ini:

var script:HTMLScriptElement = document.getElementsByName("script")[0];
alert(script.type);

tapi itu memberi saya kesalahan:

Cannot convert 'Node' to 'HTMLScriptElement': Type 'Node' is missing property 'defer' from type 'HTMLScriptElement'
(elementName: string) => NodeList

Saya tidak dapat mengakses anggota 'type' dari elemen skrip kecuali saya melemparkannya ke tipe yang benar, tetapi saya tidak tahu bagaimana melakukan ini. Saya mencari dokumen & sampel, tetapi saya tidak dapat menemukan apa pun.


Perhatikan bahwa masalah casting ini tidak ada lagi di 0,9 - Lihat jawaban oleh @Steve di bawah ini.
Greg Gum

@GregGum Saya tidak melihat jawaban oleh Steve
Steve Schrab

Jawaban:


255

TypeScript menggunakan '<>' untuk mengelilingi gips, jadi yang di atas menjadi:

var script = <HTMLScriptElement>document.getElementsByName("script")[0];

Namun, sayangnya Anda tidak dapat melakukan:

var script = (<HTMLScriptElement[]>document.getElementsByName(id))[0];

Anda mendapatkan kesalahan

Cannot convert 'NodeList' to 'HTMLScriptElement[]'

Tetapi Anda dapat melakukannya:

(<HTMLScriptElement[]><any>document.getElementsByName(id))[0];

saya pikir mereka harus melihat ini lebih jauh, misalkan Anda menggunakan $ ('[type: input]'). masing-masing (fungsi (indeks, elemen) dan Anda perlu elemen untuk dilemparkan ke HTMLInputElement atau HTMLSelectElement tergantung pada properti yang Anda perlu atur / get, casting use (<HTMLSelectElement> <any> elemen) .selectedIndex = 0; menambah () di sekitar elemen, agak jelek
rekna

+1 yang menjawab pertanyaan saya stackoverflow.com/questions/13669404/…
lhk

Dalam jangka panjang (setelah 0,9 keluar) Anda harus dapat melemparkannya ke sesuatu seperti NodeList <HtmlScriptElement>, ditambah getElementsByName akan dapat menggunakan string jenis huruf utama untuk mendapatkan hak ini tanpa casting sama sekali!
Peter Burns

3
setelah 1.0, sintaks seharusnya(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
Anda juga dapat menggunakan untuk casting. var script = document.getElementsByName ("script") [0] sebagai HTMLScriptElement;
JGFMK

36

Pada TypeScript 0.9 lib.d.tsfile menggunakan tanda tangan overload khusus yang mengembalikan tipe yang benar untuk panggilangetElementsByTagName .

Ini berarti Anda tidak perlu lagi menggunakan jenis pernyataan untuk mengubah jenis:

// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);

bagaimana Anda melakukannya dalam notasi objek? yaitu saya tidak bisa melakukan {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,}
Nikos

3
ini berfungsi: nama: (<HTMLInputElement> document.querySelector ('# app-form [name]')) nilai.,
Nikos

21

Anda selalu dapat meretas sistem menggunakan:

var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];

menggunakan <any> memungkinkan keluarnya pengecekan tipe, tidak ideal tetapi keren saat dalam pengembangan
tit

21

Jangan mengetik gips. Tidak pernah. Gunakan pelindung tipe:

const e = document.getElementsByName("script")[0];
if (!(e instanceof HTMLScriptElement)) 
  throw new Error(`Expected e to be an HTMLScriptElement, was ${e && e.constructor && e.constructor.name || e}`);
// locally TypeScript now types e as an HTMLScriptElement, same as if you casted it.

Biarkan kompiler melakukan pekerjaan untuk Anda dan mendapatkan kesalahan ketika asumsi Anda ternyata salah.

Mungkin terlihat berlebihan dalam hal ini, tetapi itu akan banyak membantu Anda jika Anda kembali lagi nanti dan mengganti pemilih, seperti menambahkan kelas yang hilang dalam dom, misalnya.


13

Berakhir dengan:

  • Arrayobjek aktual (bukan yang NodeListberpakaian seperti Array)
  • daftar yang dijamin hanya menyertakan HTMLElements, bukan Nodedicekok paksaHTMLElement s
  • perasaan hangat dan kabur untuk melakukan The Right Thing

Coba ini:

let nodeList : NodeList = document.getElementsByTagName('script');
let elementList : Array<HTMLElement> = [];

if (nodeList) {
    for (let i = 0; i < nodeList.length; i++) {
        let node : Node = nodeList[i];

        // Make sure it's really an Element
        if (node.nodeType == Node.ELEMENT_NODE) {
            elementList.push(node as HTMLElement);
        }
    }
}

Nikmati.


10

Kita bisa mengetik variabel kita dengan tipe pengembalian eksplisit :

const script: HTMLScriptElement = document.getElementsByName(id).item(0);

Atau nyatakan sebagai (diperlukan dengan TSX ):

const script = document.getElementsByName(id).item(0) as HTMLScriptElement;

Atau dalam kasus yang lebih sederhana, ketikkan sintaks sudut-braket .


Pernyataan tipe adalah seperti tipe yang dilemparkan dalam bahasa lain, tetapi tidak melakukan pemeriksaan khusus atau restrukturisasi data. Ini tidak memiliki dampak runtime, dan digunakan sepenuhnya oleh kompiler.

Dokumentasi:

TypeScript - Tipe Dasar - Ketikkan asersi


9

Hanya untuk memperjelas, ini benar.

Tidak dapat mengonversi 'NodeList' ke 'HTMLScriptElement []'

sebagai NodeListtidak array yang sebenarnya (misalnya tidak mengandung .forEach, .slice, .push, dll ...).

Jadi jika itu dikonversi ke HTMLScriptElement[]dalam sistem tipe, Anda tidak akan mendapatkan kesalahan ketik jika Anda mencoba memanggil Array.prototypeanggota di dalamnya pada waktu kompilasi, tetapi itu akan gagal pada waktu berjalan.


1
memang benar, namun tidak sepenuhnya berguna. alternatifnya adalah pergi melalui 'apa saja' yang tidak menyediakan jenis yang berguna memeriksa apa pun ...
Spongman

3

Ini tampaknya untuk menyelesaikan masalah, dengan menggunakan [index: TYPE]tipe akses array, tepuk tangan.

interface ScriptNodeList extends NodeList {
    [index: number]: HTMLScriptElement;
}

var script = ( <ScriptNodeList>document.getElementsByName('foo') )[0];

1

Dapat dipecahkan dalam file deklarasi (lib.d.ts) jika TypeScript akan mendefinisikan HTMLCollection bukan NodeList sebagai tipe kembali.

DOM4 juga menetapkan ini sebagai jenis pengembalian yang benar, tetapi spesifikasi DOM yang lebih lama kurang jelas.

Lihat juga http://typescript.codeplex.com/workitem/252


0

Karena itu NodeList, bukan Array, Anda seharusnya tidak benar-benar menggunakan tanda kurung atau casting Array. Cara properti untuk mendapatkan simpul pertama adalah:

document.getElementsByName(id).item(0)

Anda bisa saja melemparkan itu:

var script = <HTMLScriptElement> document.getElementsByName(id).item(0)

Atau, perluas NodeList:

interface HTMLScriptElementNodeList extends NodeList
{
    item(index: number): HTMLScriptElement;
}
var scripts = <HTMLScriptElementNodeList> document.getElementsByName('script'),
    script = scripts.item(0);

1
UPDATE Casting sekarang terlihat seperti ini: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Mike Keesey

Artinya, "terlihat seperti ini" untuk TS 2.3.
markeissler

0

Saya juga akan merekomendasikan panduan sitepen

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (lihat di bawah) dan https://www.sitepen.com/blog/2014/08/22/advanced -type-konsep-kelas-tipe /

TypeScript juga memungkinkan Anda untuk menentukan tipe pengembalian yang berbeda ketika string yang tepat disediakan sebagai argumen untuk suatu fungsi. Sebagai contoh, deklarasi ambient TypeScript untuk metode createElement DOM terlihat seperti ini:

createElement(tagName: 'a'): HTMLAnchorElement;
createElement(tagName: 'abbr'): HTMLElement;
createElement(tagName: 'address'): HTMLElement;
createElement(tagName: 'area'): HTMLAreaElement;
// ... etc.
createElement(tagName: string): HTMLElement;

Ini berarti, dalam TypeScript, ketika Anda memanggil misalnya document.createElement ('video'), TypeScript tahu nilai kembali adalah HTMLVideoElement dan akan dapat memastikan Anda berinteraksi dengan benar dengan DOM Video API tanpa perlu mengetikkan menegaskan.


0
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];    
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.