TypeScript: кастинг HTMLElement


198

Кто-нибудь знает, как привести в 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.9 - см. Ответ @Steve ниже.
Грег Гам

@GregGum Я не вижу ответа от Стива
Стив Шраб

Ответы:


255

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

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

+1 ответил на мой вопрос stackoverflow.com/questions/13669404/…
lhk

В долгосрочной перспективе (после выхода 0.9) вы сможете привести его к чему-то вроде NodeList <HtmlScriptElement>, плюс getElementsByName сможет использовать переопределения строкового литерала, чтобы получить это право без какого-либо приведения!
Питер Бернс

3
после 1.0 синтаксис должен быть(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
Вы также можете использовать как для приведения. var script = document.getElementsByName ("script") [0] as HTMLScriptElement;
JGFMK

36

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

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

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

как вы делаете это в объектной нотации? то есть я не могу сделать {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,}
Никос

3
это сработало: name: (<HTMLInputElement> document.querySelector ('# app-form [name]')). value,
Никос

22

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

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.


21

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

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

использование <any> позволяет избежать проверки типов, не идеально, но круто во время разработки
tit

13

В итоге:

  • фактический 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);
        }
    }
}

Наслаждаться.


10

Мы могли бы напечатать нашу переменную с явным типом возврата :

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

Или утверждать как (необходимо с TSX ):

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

Или в более простых случаях утверждать с синтаксисом угловых скобок .


Утверждение типа похоже на приведение типов в других языках, но не выполняет никакой специальной проверки или реструктуризации данных. Он не влияет на время выполнения и используется исключительно компилятором.

Документация:

TypeScript - Основные типы - Утверждения типа


9

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

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

как NodeListэто не реальный массив (например , он не содержит .forEach, .slice, .pushи т.д. ...).

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


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

3

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

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

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

1

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

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

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


0

Поскольку это, а NodeListне an 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);

1
ОБНОВЛЕНИЕ Кастинг теперь выглядит так: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Майк Кизи

То есть «выглядит так» для TS 2.3.
Markeissler

0

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

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (см. ниже) и https://www.sitepen.com/blog/2014/08/22/advanced -typescript-понятия-классы-типов /

TypeScript также позволяет указывать различные типы возвращаемых данных, когда точная строка предоставляется в качестве аргумента функции. Например, объявление окружения TypeScript для метода 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, и сможет гарантировать, что вы правильно взаимодействуете с DOM Video API без необходимости вводить assert.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.