TypeScript: Casting von HTMLElement


197

Weiß jemand, wie man TypeScript umsetzt?

Ich versuche das zu tun:

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

aber es gibt mir einen Fehler:

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

Ich kann nicht auf das 'type'-Mitglied des Skriptelements zugreifen, es sei denn, ich habe es in den richtigen Typ umgewandelt, aber ich weiß nicht, wie das geht. Ich habe die Dokumente und Beispiele durchsucht, aber nichts gefunden.


Beachten Sie, dass dieses Casting-Problem in 0.9 nicht mehr besteht - siehe Antwort von @Steve unten.
Greg Gum

@ GregGum Ich sehe keine Antwort von einem Steve
Steve Schrab

Antworten:


255

TypeScript verwendet '<>', um Casts zu umgeben.

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

Leider können Sie nicht:

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

Sie erhalten den Fehler

Cannot convert 'NodeList' to 'HTMLScriptElement[]'

Aber Sie können tun:

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

Ich denke, sie sollten dies weiter untersuchen, nehmen wir an, Sie verwenden $ ('[Typ: Eingabe]'). each (Funktion (Index, Element) und Sie müssen das Element in HTMLInputElement oder HTMLSelectElement umwandeln, je nachdem, welche Eigenschaft Sie festlegen müssen / get, Casting use (<HTMLSelectElement> <any> Element) .selectedIndex = 0; fügt () um Element hinzu, irgendwie hässlich
rekna

+1, die meine Frage beantwortete stackoverflow.com/questions/13669404/…
lhk

Auf lange Sicht (nachdem 0.9 veröffentlicht wurde) sollten Sie in der Lage sein, es in etwas wie NodeList <HtmlScriptElement> umzuwandeln, und getElementsByName kann Overrides vom Typ String-Literal verwenden, um dies ohne Casting richtig zu machen!
Peter Burns

3
nach 1.0 sollte die Syntax sein(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
Sie können auch als Cast verwenden. var script = document.getElementsByName ("script") [0] als HTMLScriptElement;
JGFMK

36

Ab TypeScript 0.9 verwendet die lib.d.tsDatei spezielle Überladungssignaturen, die die richtigen Typen für Aufrufe an zurückgeben getElementsByTagName.

Dies bedeutet, dass Sie keine Typzusicherungen mehr verwenden müssen, um den Typ zu ändern:

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

Wie macht man das in Objektnotation? dh ich kann nicht {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,}
Nikos

3
Dies funktionierte: name: (<HTMLInputElement> document.querySelector ('# app-form [name]')). value,
Nikos

21

Sie können das Typsystem immer hacken, indem Sie:

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

Die Verwendung von <any> ermöglicht die Flucht vor der Typprüfung, nicht ideal, aber während der Entwicklung cool
tit

21

Geben Sie keine Besetzung ein. Noch nie. Verwenden Sie Typschutz:

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.

Lassen Sie den Compiler die Arbeit für Sie erledigen und erhalten Sie Fehler, wenn sich Ihre Annahmen als falsch herausstellen.

In diesem Fall sieht es vielleicht übertrieben aus, aber es hilft Ihnen sehr, wenn Sie später wiederkommen und den Selektor ändern, z. B. indem Sie eine Klasse hinzufügen, die im Dom fehlt.


13

Am Ende:

  • ein tatsächliches ArrayObjekt (nicht als NodeListverkleidet Array)
  • Eine Liste, die garantiert nur s enthält HTMLElementsund nicht Nodezwangsweise in HTMLElements umgewandelt wird
  • ein warmes, verschwommenes Gefühl, das Richtige zu tun

Versuche dies:

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

Genießen.


10

Wir könnten unsere Variable mit einem expliziten Rückgabetyp eingeben :

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

Oder behaupten Sie als (benötigt mit TSX ):

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

Oder in einfacheren Fällen mit spitzer Klammer- Syntax behaupten .


Eine Typzusicherung ähnelt einer Typumwandlung in anderen Sprachen, führt jedoch keine spezielle Überprüfung oder Umstrukturierung von Daten durch. Es hat keine Auswirkungen auf die Laufzeit und wird ausschließlich vom Compiler verwendet.

Dokumentation:

TypeScript - Grundtypen - Typzusicherungen


9

Nur zur Klarstellung, das ist richtig.

'NodeList' kann nicht in 'HTMLScriptElement [] konvertiert werden'

als NodeListnicht eine tatsächliche Array ist (zB es nicht enthält .forEach, .slice, .push, etc ...).

Wenn es also HTMLScriptElement[]im Typsystem konvertiert würde, würden Sie keine Typfehler erhalten, wenn Sie versuchen würden, Array.prototypeMitglieder zur Kompilierungszeit darauf aufzurufen , aber es würde zur Laufzeit fehlschlagen.


1
Zugegeben, das ist richtig, aber nicht ganz nützlich. Die Alternative ist, über 'any' zu gehen, was keinerlei nützliche Typprüfung bietet ...
Spongman

3

Dies scheint das Problem zu lösen, indem der [index: TYPE]Array-Zugriffstyp verwendet wird.

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

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

1

Könnte in der Deklarationsdatei (lib.d.ts) gelöst werden, wenn TypeScript HTMLCollection anstelle von NodeList als Rückgabetyp definieren würde.

DOM4 gibt dies auch als korrekten Rückgabetyp an, ältere DOM-Spezifikationen sind jedoch weniger klar.

Siehe auch http://typescript.codeplex.com/workitem/252


0

Da es ein NodeList, kein ist Array, sollten Sie nicht wirklich Klammern oder Casting verwenden Array. Die Eigenschaftsmethode zum Abrufen des ersten Knotens lautet:

document.getElementsByName(id).item(0)

Sie können das einfach besetzen:

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

Oder verlängern Sie NodeList:

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

1
UPDATE Casting sieht jetzt so aus: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Mike Keesey

Das heißt, "sieht so aus" für TS 2.3.
Markissler

0

Ich würde auch die Sitepen-Anleitungen empfehlen

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (siehe unten) und https://www.sitepen.com/blog/2014/08/22/advanced -typescript-Konzepte-Klassen-Typen /

Mit TypeScript können Sie auch verschiedene Rückgabetypen angeben, wenn eine genaue Zeichenfolge als Argument für eine Funktion angegeben wird. Die Umgebungsdeklaration von TypeScript für die createElement-Methode des DOM sieht beispielsweise folgendermaßen aus:

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

Wenn Sie in TypeScript z. B. document.createElement ('video') aufrufen, weiß TypeScript, dass der Rückgabewert ein HTMLVideoElement ist, und kann sicherstellen, dass Sie korrekt mit der DOM-Video-API interagieren, ohne assert eingeben zu müssen.


0
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];    
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.