Кто-нибудь знает, как сделать в 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' элемента script, если я не применил его к правильному типу, но я не знаю, как это сделать. Я искал документы и образцы, но ничего не нашел.
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];
Как и в TypeScript 0.9, файл lib.d.ts
использует специализированные сигнатуры перегрузки, которые возвращают правильные типы для вызовов getElementsByTagName
.
Это означает, что вам больше не нужно использовать утверждения типа для изменения типа:
// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);
Вы всегда можете взломать систему типов, используя:
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
В итоге:
Array
(а не NodeList
, наряженный как Array
)HTMLElements
, а не Node
с принудительным нажатием на HTMLElement
sПопробуйте следующее:
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 really an Element
if (node.nodeType == Node.ELEMENT_NODE) {
elementList.push(node as HTMLElement);
}
}
}
Enjoy.
Чтобы уточнить, это правильно.
Невозможно преобразовать 'NodeList' в 'HTMLScriptElement []'
как NodeList
не является фактическим массивом (например, он не содержит .forEach
, .slice
, .push
и т.д.).
Таким образом, если бы он преобразовывался в HTMLScriptElement[]
в системе типов, вы не получали бы никаких ошибок типа, если бы вы пытались вызвать Array.prototype
членов на нем во время компиляции, но это не сработало во время выполнения.
Не печатайте. Никогда. Использовать защитные устройства типа:
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, например.
Это, похоже, решает проблему, используя тип доступа к массиву [index: TYPE]
, приветствия.
interface ScriptNodeList extends NodeList {
[index: number]: HTMLScriptElement;
}
var script = ( <ScriptNodeList>document.getElementsByName('foo') )[0];
Может быть решено в файле декларации (lib.d.ts), если TypeScript будет определять HTMLCollection вместо NodeList как возвращаемый тип.
DOM4 также указывает это как правильный тип возврата, но более старые спецификации DOM менее ясны.
Я бы также рекомендовал путеводители на сайтах
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 s эмбиентная декларация для метода createElement DOM выглядит следующим образом:
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 и сможет гарантировать, что вы взаимодействуете правильно с API-интерфейсом DOM без необходимости вводить assert.
Так как это a NodeList
, а не Array
, вы не должны использовать скобки или кастинг для Array
. Свойство способ получить первый node:
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);
const script = document.getElementsByName(id).item(0) as HTMLScriptElement;