任何人都知道如何使用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
我无法访问脚本元素的'type'成员,除非我将其转换为正确的类型,但我不知道如何执行此操作。我搜索了文档&样品,但我找不到任何东西。
答案 0 :(得分:232)
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];
答案 1 :(得分:34)
从TypeScript 0.9开始,lib.d.ts
文件使用专门的重载签名,为getElementsByTagName
的调用返回正确的类型。
这意味着您不再需要使用类型断言来更改类型:
// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);
答案 2 :(得分:21)
您总是可以使用以下方式破解类型系统:
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
答案 3 :(得分:16)
不要输入演员表。决不。使用型号防护:
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中缺少的类,例如。
答案 4 :(得分:11)
最终:
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);
}
}
}
享受。
答案 5 :(得分:9)
只是澄清一下,这是正确的。
无法将'NodeList'转换为'HTMLScriptElement []'
由于NodeList
不是实际数组(例如,它不包含.forEach
,.slice
,.push
等...)。
因此,如果它确实在类型系统中转换为HTMLScriptElement[]
,那么如果您在编译时尝试在其上调用Array.prototype
成员,则不会出现类型错误,但它会在运行时失败
答案 6 :(得分:4)
更新示例:
const script: HTMLScriptElement = document.getElementsByName(id).item(0) as HTMLScriptElement;
文档:
答案 7 :(得分:3)
这似乎解决了这个问题,使用[index: TYPE]
数组访问类型,欢呼。
interface ScriptNodeList extends NodeList {
[index: number]: HTMLScriptElement;
}
var script = ( <ScriptNodeList>document.getElementsByName('foo') )[0];
答案 8 :(得分:1)
如果TypeScript将HTMLCollection定义为NodeList而不是NodeList作为返回类型,则可以在声明文件(lib.d.ts)中解决。
DOM4还将此指定为正确的返回类型,但旧的DOM规范不太清楚。
答案 9 :(得分:0)
由于它是NodeList
,而不是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);
答案 10 :(得分: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还允许您在指定时指定不同的返回类型 确切字符串作为函数的参数提供。例如, 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中,当您调用例如 document.createElement('video'),TypeScript知道返回值是 一个HTMLVideoElement,将能够确保您正在进行交互 正确使用DOM Video API而无需输入assert。
答案 11 :(得分:0)
$adddata_PRST = $MYPDO->prepare("INSERT INTO tblData (AddDate, Price) VALUES(NOW(), :Price)");
答案 12 :(得分:0)
与其使用类型断言,类型保护或any
来解决问题,更优雅的解决方案是使用泛型来指示您所要使用的元素的类型选择。
不幸的是,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
。
答案 13 :(得分:0)
作为 CertainPerformance 的 answer 的扩展,如果您利用 declaration merging 来扩充标准定义库的 Document
接口,您可以为 { 添加通用覆盖{1}} 方法(或与此相关的任何其他方法),参数默认设置为 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>
列表,因为只能合并相同的声明。