TypeScript: casting HTMLElement

198

Czy ktoś wie, jak przesyłać w TypeScript?

Próbuję to zrobić:

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

ale daje mi błąd:

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

Nie mogę uzyskać dostępu do elementu „type” elementu skryptu, chyba że przerzucę go na poprawny typ, ale nie wiem, jak to zrobić. Przeszukałem dokumenty i próbki, ale nic nie znalazłem.

Gąbczasty
źródło
Pamiętaj, że ten problem z rzutowaniem nie występuje już w wersji 0.9 - Zobacz odpowiedź @Steve poniżej.
Greg Gum
@GregGum Nie widzę odpowiedzi Steve
Steve Schrab

Odpowiedzi:

255

TypeScript używa „<>” do otaczania rzutów, więc powyższe staje się:

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

Niestety nie możesz zrobić:

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

Wystąpił błąd

Cannot convert 'NodeList' to 'HTMLScriptElement[]'

Ale możesz zrobić:

(<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
Gąbczasty
źródło
myślę, że powinni przyjrzeć się temu dalej, przypuśćmy, że używasz $ („[type: input]”). each (funkcja (indeks, element) i potrzebujesz elementu do rzutowania na HTMLInputElement lub HTMLSelectElement w zależności od właściwości, którą musisz ustawić / dostać, rzucając wykorzystania (<HTMLSelectElement> <Any> element) .selectedIndex = 0; dodaje () wokół elementu, rodzaj brzydkiego
rekna
+1, która odpowiedziała na moje pytanie stackoverflow.com/questions/13669404/...
lhk
Na dłuższą metę (po wyzerowaniu 0.9) powinieneś być w stanie rzutować go na coś takiego jak NodeList <HtmlScriptElement>, a ponadto getElementsByName będzie mógł użyć przesłonięcia literałego w postaci łańcucha, aby uzyskać to poprawnie bez żadnego rzutowania!
Peter Burns,
3
po 1.0 składnia powinna wyglądać następująco(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang,
1
Możesz także użyć jako rzutu. var script = document.getElementsByName („skrypt”) [0] jako HTMLScriptElement;
JGFMK
36

Począwszy od TypeScript 0.9, lib.d.tsplik używa specjalistycznych sygnatur przeciążenia, które zwracają prawidłowe typy wywołań getElementsByTagName.

Oznacza to, że nie trzeba już używać asercji typu, aby zmienić typ:

// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);
Fenton
źródło
jak to robisz w notacji obiektowej? tzn. nie mogę zrobić {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). wartość,}
Nikos
3
to zadziałało: nazwa: (<HTMLInputElement> document.querySelector ('# app-form [name]')). wartość,
Nikos
21

Zawsze możesz zhakować system typu, używając:

var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
Jack128
źródło
użycie <any> pozwala na uniknięcie sprawdzania typu, nie jest to idealne, ale fajne w trakcie opracowywania
tit
21

Nie wpisuj obsady. Nigdy. Użyj osłon typu:

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.

Pozwól kompilatorowi wykonać pracę za Ciebie i popełniaj błędy, gdy Twoje założenia okażą się błędne.

W tym przypadku może to wyglądać na przesadne, ale bardzo ci pomoże, jeśli wrócisz później i zmienisz selektor, na przykład dodając klasę, której brakuje w domenie.

Benoit B.
źródło
13

Aby skończyć z:

  • rzeczywisty Arrayprzedmiot (nie NodeListprzebrany za Array)
  • lista, która na pewno obejmuje tylko HTMLElements, Nodea nie s-casted do HTMLElements
  • ciepłe, niewyraźne uczucie, by zrobić Właściwą Rzecz

Spróbuj tego:

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

Cieszyć się.

Johannes Fahrenkrug
źródło
10

Możemy wpisać naszą zmienną z jawnym typem zwrotu :

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

Lub potwierdź jako (potrzebne w TSX ):

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

Lub w prostszych przypadkach stwierdzaj ze składnią nawiasu kątowego .


Asercja typu jest jak rzutowany w innych językach, ale nie przeprowadza specjalnego sprawdzania ani restrukturyzacji danych. Nie ma wpływu na środowisko uruchomieniowe i jest używany wyłącznie przez kompilator.

Dokumentacja:

TypeScript - Typy podstawowe - Asercje typu

Lew
źródło
9

Tylko dla wyjaśnienia, to jest poprawne.

Nie można przekonwertować „NodeList” na „HTMLScriptElement []”

jak NodeListnie jest rzeczywiste array (np nie zawiera .forEach, .slice, .push, etc ...).

Tak więc, jeśli przekonwertowano go HTMLScriptElement[]na system typów, nie wystąpiłyby żadne błędy typu, gdybyś próbował wywołać Array.prototypena nim członków w czasie kompilacji, ale to się nie powiedzie w czasie wykonywania.

Bill Ticehurst
źródło
1
przyznane, że jest poprawne, ale nie do końca przydatne. alternatywą jest przejście przez „any”, co nie zapewnia żadnego przydatnego sprawdzania typu ...
Spongman
3

To wydaje się rozwiązać problem, używając [index: TYPE]typu dostępu do tablicy, na zdrowie.

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

var script = ( <ScriptNodeList>document.getElementsByName('foo') )[0];
Tobias Cudnik
źródło
1

Można rozwiązać w pliku deklaracji (lib.d.ts), jeśli TypeScript zdefiniuje HTMLCollection zamiast NodeList jako typ zwracany.

DOM4 określa również to jako poprawny typ zwrotu, ale starsze specyfikacje DOM są mniej jasne.

Zobacz także http://typescript.codeplex.com/workitem/252

Piotr
źródło
0

Ponieważ jest to, a NodeListnie Array, tak naprawdę nie powinieneś używać nawiasów ani rzutować Array. Właściwym sposobem na uzyskanie pierwszego węzła jest:

document.getElementsByName(id).item(0)

Możesz po prostu rzucić:

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

Lub przedłuż NodeList:

interface HTMLScriptElementNodeList extends NodeList
{
    item(index: number): HTMLScriptElement;
}
var scripts = <HTMLScriptElementNodeList> document.getElementsByName('script'),
    script = scripts.item(0);
Mike Keesey
źródło
1
AKTUALIZACJA const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Przesyłanie
To znaczy „wygląda tak” dla TS 2.3.
markeissler
0

Poleciłbym również przewodniki po sitepen

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (patrz poniżej) i https://www.sitepen.com/blog/2014/08/22/advanced -typescript-concept-class-types /

TypeScript pozwala również określić różne typy zwracanych znaków, gdy dokładny ciąg znaków jest podany jako argument funkcji. Na przykład deklaracja otoczenia TypeScript dla metody createElement DOM wygląda następująco:

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

Oznacza to, że w TypeScript podczas wywoływania np. Document.createElement („wideo”), TypeScript wie, że zwracaną wartością jest HTMLVideoElement i będzie w stanie zapewnić, że poprawnie współpracujesz z DOM Video API bez potrzeby wpisywania aser.

sebilasse
źródło
0
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];    
Radwan Ayoub
źródło