TypeScript: transmitindo HTMLElement


197

Alguém sabe como transmitir em TypeScript?

Estou tentando fazer isso:

var script:HTMLScriptElement = document.getElementsByName("script")[0];
alert(script.type);

mas está me dando um erro:

Cannot convert 'Node' to 'HTMLScriptElement': Type 'Node' is missing property 'defer' from type 'HTMLScriptElement'
(elementName: string) => NodeList

Não consigo acessar o membro 'type' do elemento de script, a menos que seja convertido para o tipo correto, mas não sei como fazer isso. Pesquisei os documentos e as amostras, mas não consegui encontrar nada.


Observe que esse problema de transmissão não existe mais em 0,9 - veja a resposta de @Steve abaixo.
Greg Gum

@GregGum eu não estou vendo uma resposta por um Steve
Steve Schrab

Respostas:


255

O TypeScript usa '<>' para cercar as transmissões, de modo que o acima se torna:

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

No entanto, infelizmente você não pode fazer:

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

Você recebe o erro

Cannot convert 'NodeList' to 'HTMLScriptElement[]'

Mas você pode fazer:

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

Eu acho que eles deveriam olhar mais adiante, suponha que você use $ ('[type: input]'). each (function (index, element) e você precisa que o elemento seja convertido para HTMLInputElement ou HTMLSelectElement, dependendo da propriedade que você precisa definir / get, lançando uso (<HTMLSelectElement> <qualquer> elemento) .selectedIndex = 0; adiciona () em torno de elemento, tipo de feio
rekna

+1 que respondeu à minha pergunta stackoverflow.com/questions/13669404/…
lhk 02/12/12

A longo prazo (após o término do 0.9), você poderá convertê-lo para algo como NodeList <HtmlScriptElement>, e getElementsByName poderá usar substituições de tipos literais de strings para obter esse resultado sem nenhuma conversão!
Peter Burns,

3
após 1.0, a sintaxe deve ser(<NodeListOf<HTMLScriptElement>>document.getElementsByName(id))[0];
Will Huang

1
Você também pode usar como transmitir. var script = document.getElementsByName ("script") [0] como HTMLScriptElement;
JGFMK 02/09

36

A partir do TypeScript 0.9, o lib.d.tsarquivo usa assinaturas especializadas de sobrecarga que retornam os tipos corretos para chamadas paragetElementsByTagName .

Isso significa que você não precisa mais usar asserções de tipo para alterar o tipo:

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

como você faz isso em notação de objeto? ou seja, eu não posso fazer {name: <HTMLInputElement>: document.querySelector ('# app-form [name]'). value,} '
Nikos

3
isso funcionou: Nome: (<HTMLInputElement> document.querySelector ( '# app-forma [nome]')) valor,.
Nikos

21

Você sempre pode hackear o sistema de tipos usando:

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

usando <any> tipo permite escapar verificação, não é o ideal, mas esfriar enquanto em desenvolvimento
tit

21

Não digite elenco. Nunca. Use proteções de tipo:

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.

Deixe o compilador fazer o trabalho por você e cometer erros quando suas suposições forem erradas.

Pode parecer um exagero nesse caso, mas ajudará bastante se você voltar mais tarde e alterar o seletor, como adicionar uma classe que está faltando no dom, por exemplo.


13

Para terminar com:

  • um Arrayobjeto real (não NodeListvestido como um Array)
  • uma lista que é garantida para incluir apenas HTMLElements, não Nodeé lançada à força paraHTMLElement s
  • um sentimento confuso e quente de fazer a coisa certa

Tente o seguinte:

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);
        }
    }
}

Aproveitar.


10

Poderíamos digitar nossa variável com um tipo de retorno explícito :

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

Ou afirme como (necessário com o TSX ):

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

Ou, em casos mais simples, afirme com a sintaxe entre colchetes angulares .


Uma asserção de tipo é como uma conversão de tipo em outros idiomas, mas não realiza nenhuma verificação ou reestruturação especial dos dados. Não tem impacto no tempo de execução e é usado exclusivamente pelo compilador.

Documentação:

TypeScript - Tipos básicos - asserções de tipo


9

Apenas para esclarecer, isso está correto.

Não é possível converter 'NodeList' em 'HTMLScriptElement []'

como NodeListnão é uma matriz real (por exemplo, não contém .forEach, .slice, .push, etc ...).

Portanto, se ele fosse convertido para HTMLScriptElement[]no sistema de tipos, você não obteria erros de tipo se tentasse chamar Array.prototypemembros nele no tempo de compilação, mas falharia no tempo de execução.


1
concedido que seja correto, porém não totalmente útil. a alternativa é ir via 'qualquer' que fornece nenhum tipo útil verificando qualquer ...
Spongman

3

Isso parece resolver o problema, usando o [index: TYPE]tipo de acesso à matriz, felicidades.

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

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

1

Pode ser resolvido no arquivo de declaração (lib.d.ts) se o TypeScript definir HTMLCollection em vez de NodeList como um tipo de retorno.

O DOM4 também especifica isso como o tipo de retorno correto, mas as especificações DOM mais antigas são menos claras.

Consulte também http://typescript.codeplex.com/workitem/252


0

Como é um NodeList, não um Array, você realmente não deveria usar colchetes ou moldar Array. A maneira da propriedade de obter o primeiro nó é:

document.getElementsByName(id).item(0)

Você pode apenas transmitir isso:

var script = <HTMLScriptElement> document.getElementsByName(id).item(0)

Ou estenda NodeList:

interface HTMLScriptElementNodeList extends NodeList
{
    item(index: number): HTMLScriptElement;
}
var scripts = <HTMLScriptElementNodeList> document.getElementsByName('script'),
    script = scripts.item(0);

1
ATUALIZAÇÃO A const script = document.getElementsByName(id).item(0) as HTMLScriptElement;
transmissão

Ou seja, "fica assim" para o TS 2.3.
Markeissler

0

Eu também recomendaria os guias do sitepen

https://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/ (veja abaixo) e https://www.sitepen.com/blog/2014/08/22/advanced -typescript-conceitos-classes-tipos /

O TypeScript também permite especificar diferentes tipos de retorno quando uma string exata é fornecida como argumento para uma função. Por exemplo, a declaração de ambiente do TypeScript para o método createElement do DOM se parece com isso:

createElement(tagName: 'a'): HTMLAnchorElement;
createElement(tagName: 'abbr'): HTMLElement;
createElement(tagName: 'address'): HTMLElement;
createElement(tagName: 'area'): HTMLAreaElement;
// ... etc.
createElement(tagName: string): HTMLElement;

Isso significa que, no TypeScript, quando você chama, por exemplo, document.createElement ('video'), o TypeScript sabe que o valor de retorno é um HTMLVideoElement e poderá garantir que você esteja interagindo corretamente com a API de vídeo do DOM sem a necessidade de digitar assert.


0
var script = (<HTMLScriptElement[]><any>document.getElementsByName(id))[0];    
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.