TypeScript: кастинг HTMLElement

128

Кто-нибудь знает, как сделать в 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, если я не применил его к правильному типу, но я не знаю, как это сделать. Я искал документы и образцы, но ничего не нашел.

  • 0
    Обратите внимание, что эта проблема приведения больше не существует в 0.9 - см. Ответ @Steve ниже.
  • 0
    @GregGum Я не вижу ответа от Стива
Теги:

10 ответов

194
Лучший ответ

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
    Я думаю, что это должно быть рассмотрено дальше ...
  • 0
    я думаю, что они должны изучить это дальше, предположим, что вы используете $ ('[type: input]'). each (function (index, element)), и вам нужно, чтобы элемент был приведен к HTMLInputElement или HTMLSelectElement в зависимости от того, какое свойство вам нужно установить / get, использование приведения (<HTMLSelectElement> <any> элемент) .selectedIndex = 0; добавление () вокруг элемента, что-то уродливое
Показать ещё 9 комментариев
30

Как и в TypeScript 0.9, файл lib.d.ts использует специализированные сигнатуры перегрузки, которые возвращают правильные типы для вызовов getElementsByTagName.

Это означает, что вам больше не нужно использовать утверждения типа для изменения типа:

// No type assertions needed
var script: HTMLScriptElement = document.getElementsByTagName('script')[0];
alert(script.type);
  • 0
    как вы делаете это в объектной нотации? то есть я не могу сделать {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,}
  • 2
    это сработало: name: (<HTMLInputElement> document.querySelector ('# app-form [name]')). value,
Показать ещё 1 комментарий
15

Вы всегда можете взломать систему типов, используя:

var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];
  • 0
    использование <any> позволяет избежать проверки типов, не идеально, но круто во время разработки
9

В итоге:

  • фактический объект Array (а не NodeList, наряженный как Array)
  • список, который, как гарантируется, включает только HTMLElements, а не Node с принудительным нажатием на HTMLElement s
  • теплое нечеткое чувство, чтобы сделать The Right Thing

Попробуйте следующее:

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.

9

Чтобы уточнить, это правильно.

Невозможно преобразовать 'NodeList' в 'HTMLScriptElement []'

как NodeList не является фактическим массивом (например, он не содержит .forEach, .slice, .push и т.д.).

Таким образом, если бы он преобразовывался в HTMLScriptElement[] в системе типов, вы не получали бы никаких ошибок типа, если бы вы пытались вызвать Array.prototype членов на нем во время компиляции, но это не сработало во время выполнения.

  • 1
    Конечно, это правильно, но не совсем полезно. альтернатива состоит в том, чтобы пройти через 'any', который не дает никакой проверки типа ...
4

Не печатайте. Никогда. Использовать защитные устройства типа:

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, например.

3

Это, похоже, решает проблему, используя тип доступа к массиву [index: TYPE], приветствия.

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

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

Может быть решено в файле декларации (lib.d.ts), если TypeScript будет определять HTMLCollection вместо NodeList как возвращаемый тип.

DOM4 также указывает это как правильный тип возврата, но более старые спецификации DOM менее ясны.

См. также http://typescript.codeplex.com/workitem/252

1

Я бы также рекомендовал путеводители на сайтах

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.

1

Так как это 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);
  • 1
    ОБНОВЛЕНИЕ Приведение теперь выглядит следующим образом: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
  • 0
    То есть «выглядит так» для TS 2.3.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню