我试着这样做:

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

我不能访问脚本元素的'type'成员,除非我将其转换为正确的类型,但我不知道如何做到这一点。我查了文件和样本,但什么都没找到。


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

澄清一下,这是正确的。

无法将“NodeList”转换为“HTMLScriptElement[]”

作为一个NodeList不是一个实际的数组(例如,它不包含. foreach, .slice, .push等…)

因此,如果它在类型系统中转换为HTMLScriptElement[],如果您尝试调用Array,则不会得到类型错误。在编译时它上的原型成员,但在运行时它将失败。


你总是可以破解类型系统使用:

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

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

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

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

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

DOM4还将此指定为正确的返回类型,但旧的DOM规范不太清楚。

参见http://typescript.codeplex.com/workitem/252


因为它是一个节点列表,而不是数组,所以不应该使用括号或强制转换为数组。获取第一个节点的属性方法是:

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

从TypeScript 0.9开始,lib.d.ts文件使用专门的重载签名,为调用getElementsByTagName返回正确的类型。

这意味着你不再需要使用类型断言来改变类型:

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

我还会推荐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还允许你指定不同的返回类型 精确字符串作为函数的参数提供。例如, TypeScript对DOM的createElement方法的环境声明 看起来是这样的:

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

这意味着,在TypeScript中,当你调用e.g.。 document.createElement('video'), TypeScript知道返回值是 一个HTMLVideoElement,将能够确保你是交互的 正确地使用DOM视频API,而不需要任何类型断言。


以…结束:

一个实际的Array对象(不是一个伪装成Array的NodeList) 一个保证只包含htmlelement的列表,而不是强制转换为htmlelement的Nodes 一种做正确事情的温暖模糊的感觉

试试这个:

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

享受。


不要进行类型转换。从来没有。使用类型保护:

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中缺少的类,它将对您有很大帮助。


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

我们可以使用显式返回类型为变量类型:

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

或assert as (TSX需要):

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

或者在更简单的情况下使用尖括号语法断言。


类型断言类似于其他语言中的类型强制转换,但不执行特殊的数据检查或重构。它对运行时没有影响,完全由编译器使用。

文档:

基本类型-类型断言


与其使用类型断言、类型保护或任何方法来解决这个问题,更优雅的解决方案是使用泛型来指示所选择的元素类型。

不幸的是,getElementsByName不是通用的,但是querySelector和querySelectorAll是通用的。(querySelector和querySelectorAll也要灵活得多,因此在大多数情况下可能更可取。)

如果你单独将一个标签名称传递给querySelector或querySelectorAll,它将自动正确地输入,因为下面这行在lib.dom.d.ts中:

querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;

例如,要选择页面上的第一个脚本标签,如您的问题,您可以这样做:

const script = document.querySelector('script')!;

就是这样——TypeScript现在可以推断出script现在是一个HTMLScriptElement。

当需要选择单个元素时使用querySelector。如果需要选择多个元素,请使用querySelectorAll。例如:

document.querySelectorAll('script')

结果类型为NodeListOf<HTMLScriptElement>。

如果需要更复杂的选择器,可以传递一个类型参数来指示将要选择的元素的类型。例如:

const ageInput = document.querySelector<HTMLInputElement>('form input[name="age"]')!;

导致ageInput被输入为HTMLInputElement。


作为cerperformance答案的扩展,如果你使用声明合并来增加标准定义库的文档接口,你可以为getElementsByName方法(或任何其他方法)添加一个泛型覆盖,参数默认设置为HTMLElement,以模拟非泛型版本的行为时,类型参数没有显式提供:

interface Document
  extends Node,
    DocumentAndElementEventHandlers,
    DocumentOrShadowRoot,
    GlobalEventHandlers,
    NonElementParentNode,
    ParentNode,
    XPathEvaluatorBase {
  getElementsByName<T extends HTMLElement>(elementName: string) : NodeListOf<T>;
}

然后在用户代码中,你可以显式地传递所需的类型:

const scripts = document.getElementsByName<HTMLScriptElement>("name"); //NodeListOf<HTMLScriptElement>

操场上


注意,您需要重新指定extends列表,因为只有相同的声明才能合并。