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


Зауважте, що це питання кастингу більше не існує в 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];

я думаю, вони повинні вивчити це далі, припустимо, ви використовуєте $ ('[тип: введення]'). / get, кастинг використання (<HTMLSelectElement> <any> елемент) .selectedIndex = 0; додає () навколо елемента, різновид некрасивого
rekna

+1 , що відповіли на моє запитання stackoverflow.com/questions/13669404 / ...
ЛХК

У довгостроковій перспективі (після того, як 0,9 вичерпано), ви повинні мати можливість передавати це на щось на зразок NodeList <HtmlScriptElement>, плюс getElementsByName зможе використовувати строкові літеральні строки, щоб отримати це право без будь-якого кастингу!
Пітер Бернс

3
після 1,0 синтаксис повинен бути(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Буде Хуан

1
Ви також можете використовувати для ролі. var script = document.getElementsByName ("скрипт") [0] як 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]') значення,}
Нікос

3
це спрацювало: name: (<HTMLInputElement> document.querySelector ('# app-form [name]')). значення,
Нікос

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.

Дозвольте компілятору зробити роботу за вас і помилитися, коли ваші припущення виявляться неправильними.

У цьому випадку це може виглядати непосильним, але це дуже допоможе вам, якщо ви повернетесь пізніше і зміните селектор, наприклад, додавши клас, який, наприклад, відсутній у домі.


21

Ви завжди можете зламати систему типів, використовуючи:

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

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

13

На закінчення:

  • фактичний 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'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
Звичайно, це правильно, але не зовсім корисно. альтернатива - перейти через "будь-яке", що не забезпечує корисної перевірки типу ...
Спонгмен

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не 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
UPDATE Кастинг зараз виглядає приблизно так: const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
Майк Кізі

Тобто "виглядає так" для TS 2.3.
markeissler

0

Я також рекомендую посібники sitepen

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, і зможе переконатися, що ви правильно взаємодієте з API DOM Video без необхідності введення ствердження.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.