在HTMLCollection上循环的打字稿

时间:2018-11-01 09:48:27

标签: typescript

我想遍历结果

document.getElementsByTagName("...");

它返回一个HTMLCollection,而不是一个数组。因此,我不能简单地使用forEach。 以下是可能的,但看起来不太好:

let elements = document.getElementsByTagName("...");
for (var i = 0, m = elements.length; i < m; i++) {
    let element = elements[i];
}

对于javascript,几乎存在完全相同的问题: For loop for HTMLCollection elements

显然,有了最新更新,现代浏览器就支持:

var list = document.getElementsByClassName("events");
for (let item of list) {
    log(item.id);
}

但是打字稿编译器抱怨:

error TS2495: Type 'NodeListOf<HTMLParagraphElement>' is not an array type or a string type.

尽管如此,它仍然可以转换为正确的Javascript。它甚至知道我在这里做什么,而不仅仅是复制源代码。编译后的输出是这样的:

var elements = main_div.getElementsByTagName("p");
for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) {
    var element = elements_1[_i];
}

这很好,因为即使在较旧的浏览器上也支持生成的代码。但是我想摆脱错误消息。

我的编译器选项是:

{
    "compilerOptions": {

        "module": "commonjs",
        "target": "es5",
        "sourceMap": true,
        "rootDir": "src",
        "lib": [
            "es2015",
            "dom"
        ]
    }
}

我确实尝试编辑我的lib选项。此特定功能是ES6的一部分,并且已进行了多次重做。因此,我在lib中测试了各种ecmascript版本,但找不到有效的设置。

6 个答案:

答案 0 :(得分:5)

如果要使用forEach,可以将其转换为数组

const elements: Element[] = Array.from(document.getElementsByTagName("..."));
elements.forEach((el: Element) => {
    // do something
})

答案 1 :(得分:2)

要摆脱错误消息,您可以将列表添加为 任何 类型。 Typescript与JavaScript的区别在于 Type 。因此,最佳做法是将类型添加到变量中。供您参考,我添加了 any 类型:

var list: any = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}

实际上,这是典型的“上下文键入”。当表达式的类型由其位置隐含时,便会发生上下文类型化。对于上面给出类型错误的代码,TypeScript类型检查器使用document.getElementsByClassName(“ events”)的类型来推断ForLoop函数的类型。如果此函数表达式不在上下文键入的位置,则 列表 的类型将为any,并且不会发出任何错误。

如果上下文类型化的表达式包含显式类型 信息,上下文类型将被忽略。

  

在许多情况下都适用上下文类型。常见的情况包括   函数调用的参数,赋值的右侧,类型   断言,对象和数组文字的成员,然后返回   陈述。上下文类型也最好充当候选类型   普通类型。[来自TypeScript文档]

答案 2 :(得分:2)

用法示例:

const inputs = document.getElementsByTagName("input");
for (let index = 0; index < inputs.length; index++) {
  const input = inputs.item(index);
}

答案 3 :(得分:0)

这不应该在typecipt中给出错误,因为for in也适用于objects

var list = document.getElementsByClassName("events");
for (let key in list) {
  if(list.hasOwnProperty(key)) {
    log(list[key].id);
  }
}

通过for of循环,您可以使用Object.keys()

var list = document.getElementsByClassName("events");
for (let key of Object.keys(list)) {
  if(list.hasOwnProperty(key)) {
    log(list[key].id);
  }
}

答案 4 :(得分:0)

打字稿编译器在指定了额外的标记downlevelIteration后支持此操作:

{
    "compilerOptions": {
        "target": "es5",
        "downlevelIteration": true
    }
}

但是,这不仅将消除错误,还将改变编译器的输出。 此输入打字稿:

function compileTest(){
  let elements = document.getElementsByTagName("p");
  for(let element of elements){
    console.log(element);
  }
}

已编译为此JavaScript:

function compileTest() {
    var e_1, _a;
    var elements = document.getElementsByTagName("p");
    try {
        for (var elements_1 = __values(elements), elements_1_1 = elements_1.next(); !elements_1_1.done; elements_1_1 = elements_1.next()) {
            var element = elements_1_1.value;
            console.log(element);
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (elements_1_1 && !elements_1_1.done && (_a = elements_1.return)) _a.call(elements_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
}

答案 5 :(得分:0)

我知道这是一个很晚才回答的问题,但我认为在线程中使用它可能会很不错...在Angular项目中,我正在寻找一种使用数组解构的方法(喜欢HTMLCollectionOf<T>的数组破坏amiright吗?),如下面的示例所示:

const [zoomControl] = document.getElementsByClassName('leaflet-control-zoom');

但是会得到错误:

“类型'HTMLCollectionOf'必须具有'Symbol.iterator' 返回iterator.ts(2488)'

的方法

此外,我还遇到了对集合进行迭代的很好的情况,例如:

const elementsWithClassName = document.getElementsByClassName('class-name');
for(const a of elementsWithClassName) {
  console.log(a)
}

我发现添加了具有以下内容的global-types-extensions.d.ts文件:

declare global {
  interface HTMLCollectionOf<T extends Element> {
    [Symbol.iterator](): Iterator<T>;
  }
}
export {};

...修复了我从TS中收到的错误/警告。

所以现在,我可以愉快地解决数组分解问题,并在任何for...of??上使用HTMLCollectionOf