我试着这样做:
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'成员,除非我将其转换为正确的类型,但我不知道如何做到这一点。我查了文件和样本,但什么都没找到。
与其使用类型断言、类型保护或任何方法来解决这个问题,更优雅的解决方案是使用泛型来指示所选择的元素类型。
不幸的是,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列表,因为只有相同的声明才能合并。
我还会推荐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,而不需要任何类型断言。
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];
因为它是一个节点列表,而不是数组,所以不应该使用括号或强制转换为数组。获取第一个节点的属性方法是:
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);