TypeScript: การหล่อ HTMLElement


198

ไม่มีใครรู้วิธีการส่งใน TypeScript หรือไม่

ฉันพยายามทำสิ่งนี้:

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

แต่มันทำให้ฉันมีข้อผิดพลาด:

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

ฉันไม่สามารถเข้าถึงสมาชิก 'ประเภท' ขององค์ประกอบสคริปต์ได้เว้นแต่ฉันจะแปลงเป็นประเภทที่ถูกต้อง แต่ฉันไม่ทราบวิธีการทำเช่นนี้ ฉันค้นหาเอกสารและตัวอย่าง แต่ฉันไม่พบอะไรเลย


โปรดทราบว่าปัญหาการส่งสัญญาณนี้ไม่มีอยู่ใน 0.9 อีกต่อไป - ดูคำตอบจาก @Steve ด้านล่าง
Greg Gum

@GregGum ฉันไม่เห็นคำตอบของ Steve
Steve Schrab

คำตอบ:


255

TypeScript ใช้ '<>' เพื่อล้อมรอบ casts ดังนั้นข้างต้นจะกลายเป็น:

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

อย่างไรก็ตามน่าเสียดายที่คุณไม่สามารถทำได้:

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

คุณได้รับข้อผิดพลาด

Cannot convert 'NodeList' to 'HTMLScriptElement[]'

แต่คุณสามารถทำได้:

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

ฉันคิดว่าพวกเขาควรพิจารณาเพิ่มเติมนี้สมมติว่าคุณใช้ $ ('[ชนิด: อินพุต]') แต่ละอัน (ฟังก์ชั่น (ดัชนีองค์ประกอบ) และคุณต้องมีองค์ประกอบที่จะส่งไปยัง HTMLInputElement หรือ HTMLSelectElement ขึ้นอยู่กับคุณสมบัติที่คุณต้องการตั้ง / get, การใช้การแคสต์ (<HTMLSelectElement> องค์ประกอบ <any>) .selectedIndex = 0; เพิ่ม () รอบองค์ประกอบ, ชนิดที่น่าเกลียด
rekna

1 ที่ตอบคำถามของฉันstackoverflow.com/questions/13669404/...
LHK

ในระยะยาว (หลังจาก 0.9 ออกมา) คุณควรจะสามารถส่งมันไปยังสิ่งที่ต้องการ NodeList <HtmlScriptElement> รวมทั้ง getElementsByName จะสามารถใช้การแทนที่ชนิดตัวอักษรของสตริงเพื่อรับสิทธิ์นี้โดยไม่ต้องทำการแคสท์เลย!
Peter Burns

3
หลังจาก 1.0 ไวยากรณ์ควรเป็น(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
คุณยังสามารถใช้เพื่อส่ง var script = document.getElementsByName ("script") [0] เป็น HTMLScriptElement;
JGFMK

36

ในฐานะของ TypeScript 0.9 lib.d.tsไฟล์ใช้ลายเซ็นโอเวอร์โหลดพิเศษที่ส่งกลับประเภทที่ถูกต้องสำหรับการโทรgetElementsByTagNameการใช้ไฟล์เฉพาะลายเซ็นเกินที่ส่งกลับประเภทที่ถูกต้องสำหรับการโทรไป

ซึ่งหมายความว่าคุณไม่จำเป็นต้องใช้การยืนยันประเภทเพื่อเปลี่ยนประเภท:

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

คุณจะทำอย่างไรในเอกสารวัตถุ? เช่นฉันไม่สามารถทำ{name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,}
Nikos

3
สิ่งนี้ใช้งานได้: ชื่อ: (<HTMLInputElement> document.querySelector ('# app-form [name]')). value.
Nikos

22

อย่าพิมพ์ตัวละคร ไม่เคย ใช้ยามประเภท:

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.

ให้คอมไพเลอร์ทำงานให้คุณและรับข้อผิดพลาดเมื่อสมมติฐานของคุณผิด

มันอาจดู overkill ในกรณีนี้ แต่มันจะช่วยคุณได้มากถ้าคุณกลับมาใหม่ในภายหลังและเปลี่ยนตัวเลือกเช่นเพิ่มคลาสที่หายไปใน dom


21

คุณสามารถแฮ็คระบบประเภทได้ตลอดเวลาโดยใช้:

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

การใช้ <any> ช่วยให้การตรวจสอบประเภทการหลบหนีไม่เหมาะ แต่จะยอดเยี่ยมในขณะที่กำลังพัฒนา
tit

13

เพื่อท้ายด้วย:

  • Arrayวัตถุจริง(ไม่ใช่NodeListแต่งตัวเป็นArray )
  • รายการที่รับประกันว่าจะรวมเฉพาะHTMLElementsไม่ใช่Nodes-casted ไปยังHTMLElements
  • ความรู้สึกเลือนที่อบอุ่นในการทำสิ่งที่ถูกต้อง

ลองสิ่งนี้:

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

สนุก.


10

เราสามารถพิมพ์ตัวแปรของเราด้วยประเภทผลตอบแทนที่ชัดเจน :

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

หรือยืนยันเป็น (จำเป็นต้องมีTSX ):

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

หรือในกรณีที่ง่ายกว่ายืนยันด้วยไวยากรณ์วงเล็บมุม


การยืนยันประเภทเป็นเหมือนนักแสดงประเภทในภาษาอื่น แต่ไม่มีการตรวจสอบพิเศษหรือปรับโครงสร้างข้อมูล มันไม่มีผลกระทบต่อรันไทม์และใช้โดยคอมไพเลอร์อย่างหมดจด

เอกสารอ้างอิง:

TypeScript - ประเภทพื้นฐาน - ยืนยันประเภท


9

เพียงชี้แจงนี้ถูกต้อง

ไม่สามารถแปลง 'NodeList' เป็น 'HTMLScriptElement []'

เป็นNodeListไม่ได้เป็นอาร์เรย์ที่เกิดขึ้นจริง (เช่นมันไม่ได้มี.forEach, .slice,.pushฯลฯ ... )

ดังนั้นหากแปลงHTMLScriptElement[]เป็นระบบชนิดคุณจะไม่ได้รับข้อผิดพลาดประเภทหากคุณพยายามโทรหาArray.prototypeสมาชิกในเวลารวบรวม แต่จะล้มเหลวในเวลาทำงาน


1
อนุญาตแล้วว่าถูกต้อง แต่ไม่มีประโยชน์ทั้งหมด อีกทางเลือกหนึ่งคือการไปผ่านทาง '' ใด ๆ ที่ให้บริการไม่มีชนิดที่มีประโยชน์ในการตรวจสอบใด ๆ ...
Spongman

3

ดูเหมือนว่าจะแก้ปัญหาโดยใช้[index: TYPE]ไชโยเข้าถึงประเภท

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

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

1

สามารถแก้ไขได้ในไฟล์การประกาศ (lib.d.ts) หาก TypeScript จะกำหนด HTMLCollection แทนที่จะเป็น NodeList เป็นชนิดส่งคืน

DOM4 ยังระบุสิ่งนี้ว่าเป็นประเภทส่งคืนที่ถูกต้อง แต่ข้อกำหนด DOM ที่เก่ากว่านั้นไม่ชัดเจน

ดูเพิ่มเติมที่http://typescript.codeplex.com/workitem/252


0

เนื่องจากเป็น a NodeListไม่ใช่ไม่ใช่Arrayคุณไม่ควรใช้วงเล็บหรือแคสArrayต์ วิธีการของคุณสมบัติในการรับโหนดแรกคือ:

document.getElementsByName(id).item(0)

คุณสามารถส่งได้:

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

หรือขยายNodeList:

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

1
อัปเดตการคัดเลือกตอนนี้มีลักษณะเช่นนี้: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Mike Keesey

นั่นคือ "ดูเหมือนว่านี้" สำหรับ TS 2.3
markeissler

0

ฉันยังจะแนะนำคำแนะนำการใช้เว็บไซต์

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (ดูด้านล่าง) และ https://www.sitepen.com/blog/2014/08/22/advanced -typescript แนวคิดคลาสประเภท /

TypeScript ยังช่วยให้คุณสามารถระบุชนิดการส่งคืนที่แตกต่างกันเมื่อมีการระบุสตริงที่แน่นอนเป็นอาร์กิวเมนต์ของฟังก์ชัน ตัวอย่างเช่นการประกาศโดยรอบของ TypeScript สำหรับวิธีการ createElement ของ DOM มีลักษณะดังนี้:

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

ซึ่งหมายความว่าใน TypeScript เมื่อคุณโทรเช่น document.createElement ('วิดีโอ') TypeScript รู้ว่าค่าส่งคืนเป็น HTMLVideoElement และจะสามารถมั่นใจได้ว่าคุณโต้ตอบอย่างถูกต้องกับ DOM Video API โดยไม่จำเป็นต้องพิมพ์คำยืนยันใด ๆ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.