How to assert a type of an HTMLElement in TypeScript?
Solution 1
TypeScript uses '<>' to surround casts, so the above becomes:
var script = <HTMLScriptElement>document.getElementsByName("script")[0];
However, unfortunately you cannot do:
var script = (<HTMLScriptElement[]>document.getElementsByName(id))[0];
You get the error
Cannot convert 'NodeList' to 'HTMLScriptElement[]'
But you can do :
(<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
Solution 2
Do not type cast. Never. Use type guards:
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.
Let the compiler do the work for you and get errors when your assumptions turn out wrong.
It may look overkill in this case, but it will help you a lot if you come back later and change the selector, like adding a class that is missing in the dom, for example.
Solution 3
As of TypeScript 0.9 the lib.d.ts
file uses specialized overload signatures that return the correct types for calls to getElementsByTagName
.
This means you no longer need to use type assertions to change the type:
// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);
Solution 4
You always can hack type system using:
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
Solution 5
We could type our variable with an explicit return type:
const script: HTMLScriptElement = document.getElementsByName(id).item(0);
Or assert as (needed with TSX):
const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Or in simpler cases assert with angle-bracket syntax.
A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler.
Documentation:
Related videos on Youtube
Spongman
Updated on May 16, 2021Comments
-
Spongman about 3 years
I'm trying to do this:
var script:HTMLScriptElement = document.getElementsByName("script")[0]; alert(script.type);
but it's giving me an error:
Cannot convert 'Node' to 'HTMLScriptElement': Type 'Node' is missing property 'defer' from type 'HTMLScriptElement' (elementName: string) => NodeList
I can't access the 'type' member of the script element unless I cast it to the correct type, but I don't know how to do this. I searched the docs & samples, but I couldn't find anything.
-
Greg Gum over 10 yearsNote that this casting issue no longer exists in 0.9 - See answer by @Steve below.
-
Steve Schrab about 7 years@GregGum I'm not seeing an answer by a Steve
-
-
Spongman over 11 yearsgranted that is correct, however not entirely useful. the alternative is to go via 'any' which provides no useful type checking whatsoever...
-
rekna over 11 yearsi think they should look into this further, suppose you use $('[type:input]').each( function(index,element) and you need element to be cast to HTMLInputElement or HTMLSelectElement depending on which property you need to set/get, casting use (<HTMLSelectElement><any>element).selectedIndex=0; adds () around element , kind of ugly
-
lhk over 11 years+1 that answered my question stackoverflow.com/questions/13669404/…
-
Peter Burns about 11 yearsIn the long run (after 0.9 is out) you should be able to cast it to something like NodeList<HtmlScriptElement>, plus getElementsByName will be able to use string literal type overrides to get this right without any casting at all!
-
Luke almost 11 yearsany is just huge, without ts would just be a joke
-
Will Huang almost 10 yearsafter 1.0, the syntax should be
(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
-
vilicvane over 9 years
any
is the bridge, but it shouldn't be applied here.NodeList
is not an array ofNode
, and shouldn't be treated as an array. A better way would be<Node[]>Array.prototype.slice.call(nodeList);
-
Laker about 8 yearsThank you. I'm sad that it has to be done like this, but it works. Better than nothing:/
-
Nikos over 7 yearshow do you do it in object notation? ie I can't do {name: <HTMLInputElement> : document.querySelector('#app-form [name]').value,}
-
Nikos over 7 yearsthis worked: name: (<HTMLInputElement> document.querySelector('#app-form [name]')).value,
-
Mike Keesey about 7 yearsUPDATE Casting now looks like this:
const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
-
markeissler about 7 yearsThat is, "looks like this" for TS 2.3.
-
JGFMK almost 7 yearsYou can also use as to cast. var script = document.getElementsByName("script")[0] as HTMLScriptElement;
-
Daedalon over 6 yearsThe recommended type to use is
HTMLInputElement
according to github.com/Microsoft/TypeScript/issues/10453. -
tit over 5 yearsusing <any> allows escaping type checking, not ideal but cool while in development
-
Richard Hunter over 3 yearsIt would seem safe here, surely? We can guarantee that e is always going to be an instance of HTMLScriptElement, can't we (unless it doesn't exist, I suppose)?
-
Souleste almost 3 yearsI couldn't seem to get any type casting to work but this worked.
-
LuanLuanLuan over 2 yearsTks! the second option work for me. The first option my lint print: Type 'HTMLElement | null' is not assignable to type 'HTMLScriptElement'. Type 'null' is not assignable to type 'HTMLScriptElement'. (is my first project em Typescript :S hahaha)