cyan
cyan

Reputation: 309

Why forEach does not exist on NodeListOf

My code:

    var checkboxes = this.element.querySelectorAll("input[type=checkbox]") as NodeListOf<HTMLInputElement>;
    checkboxes.forEach(ele => {
        var key = ele.name;
        if (data.hasOwnProperty(key)) {
            if (!this.isArray(data[key])) {
                var temp = data[key];
                data[key] = [temp];
            }
        } else {
            data[key] = [];
        }
    });

But I got an error:

error TS2339: Property 'forEach' does not exist on type 'NodeListOf'.

interface NodeListOf<TNode extends Node> extends NodeList {
    length: number;
    item(index: number): TNode;
    [index: number]: TNode;
}

interface NodeList {
    /**
     * Returns an array of key, value pairs for every entry in the list
     */
    entries(): IterableIterator<[number, Node]>;
    /**
     * Performs the specified action for each node in an list.
     * @param callbackfn  A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the list.
     * @param thisArg  An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
     */
    forEach(callbackfn: (value: Node, index: number, listObj: NodeList) => void, thisArg?: any): void;
    /**
     * Returns an list of keys in the list
     */
    keys(): IterableIterator<number>;

    /**
     * Returns an list of values in the list
     */
    values(): IterableIterator<Node>;


    [Symbol.iterator](): IterableIterator<Node>;
}

'NodeListOf' inherit from 'NodeList',and 'NodeList' has 'forEach' method,why 'forEach' does not exist on 'NodeListOf'?

Upvotes: 18

Views: 23866

Answers (2)

Daniel Kucal
Daniel Kucal

Reputation: 9232

There is no guarantee forEach will exist on this type - it can, but not necessarily (e.g. in PhantomJS and IE), so TypeScript disallows it by default. In order to iterate over it you can use:

1) Array.from():

Array.from(checkboxes).forEach((el) => { /* do something */});

2) for-in:

for (let i in checkboxes) {
  if (checkboxes.hasOwnProperty(i)) {
    console.log(checkboxes[i]);
  }
}

Upvotes: 37

Tommy May
Tommy May

Reputation: 1138

Honestly you could convert a NodeListOf to an array so that typescript will not complain about nodelist.forEach, but this is only solving the problem by adding unnecessary code. You can tell typescript to understand the native nodelist.forEach syntax by adding the dom.iterable library to your tsconfig.json. Here is an example of one of my tsconfig.json files.

{
  "compilerOptions": {
  "outDir": "./public/js/",
  "noImplicitAny": true,
  "module": "es6",
  "target": "es5",
  "allowJs": true,
  "moduleResolution": "node",
  "rootDir": "src",
  "lib": [
    "es6",
    "dom",
    "dom.iterable"
  ],
  "typeRoots": [
    "node_modules/@types"
  ],
  "removeComments": false
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "public",
    "**/*.spec.ts"
  ]
}

Not all browsers support nodelist.forEach so I would definitely polyfill it https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach

Upvotes: 14

Related Questions