TypeScript:强制转换HTMLElement


197

有人知道如何在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

除非将其强制转换为正确的类型,否则我无法访问script元素的'type'成员,但是我不知道该怎么做。我搜索了文档和样本,但找不到任何东西。


请注意,此强制转换问题在0.9中不再存在-请参见下面@Steve的回答。
格雷格·古姆

@GregGum我看不到史蒂夫的答案
史蒂夫·施拉布

Answers:


255

TypeScript使用'<>'包围强制转换,因此以上内容变为:

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];

我认为他们应该对此进行进一步研究,假设您使用$('[type:input]')。each(function(index,element),并且需要根据要设置的属性将元素强制转换为HTMLInputElement或HTMLSelectElement / get,强制转换使用(<HTMLSelectElement> <any> element).selectedIndex = 0;在元素周围添加(),有点丑陋
rekna 2012年


从长远来看(在0.9退出之后),您应该可以将其强制转换为类似NodeList <HtmlScriptElement>的对象,再加上getElementsByName将能够使用字符串文字类型替代来完全正确地执行此操作!
彼得·伯恩斯

3
在1.0之后,语法应为(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
您也可以使用as进行投射。var script = document.getElementsByName(“ script”)[0]作为HTMLScriptElement;
JGFMK '17

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

21

您始终可以使用以下方法破解类型系统:

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

使用<任何>允许逸出类型检查,不理想,但冷却,同时在显影
山雀

21

不要键入强制类型转换。决不。使用防护罩:

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.

让编译器为您完成工作,并在您的假设错误时得到错误。

在这种情况下,它看起来可能有点过大,但是如果您稍后再返回并更改选择器(例如添加dom中缺少的类),它将对您有很大帮助。


13

最后以:

  • 实际Array对象(不是NodeList打扮成Array
  • 保证只包含的列表,而HTMLElements不是Node强制转换为HTMLElement的列表
  • 做正确的事的温暖模糊的感觉

试试这个:

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
当然,这是正确的,但并不完全有用。另一种选择是通过“ any”,它不提供任何有用的类型检查...
Spongman

3

这似乎解决了问题,使用 [index: TYPE]数组访问类型,,欢呼。

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

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

1

如果TypeScript将HTMLCollection而不是NodeList定义为返回类型,则可以在声明文件(lib.d.ts)中解决。

DOM4还将其指定为正确的返回类型,但是较旧的DOM规范尚不清楚。

另请参阅http://typescript.codeplex.com/workitem/252


0

由于是a NodeList而不是an 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'5

0

我也会推荐Sitepen指南

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/(请参见下文)和 https://www.sitepen.com/blog/2014/08/22/advanced -typescript-concepts-classes-types /

当提供精确的字符串作为函数的参数时,TypeScript还允许您指定不同的返回类型。例如,DOM的createElement方法的TypeScript环境声明如下所示:

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

这意味着,在TypeScript中,当您调用例如document.createElement('video')时,TypeScript知道返回值是HTMLVideoElement,并且能够确保您与DOM Video API正确交互,而无需键入assert。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.