htmlnode.jstypescriptdomdomparser

Type 'Node | null' is not assignable to type 'Node' when trying to iterate over HTML elements in TypeScript


I have some code takes a string of raw Markdown stored in 'markdownString' and converts it to HTML with the marked.js library for display on the web browser. I am trying to grab all plain text values from the page and to store it in an array of strings by using a TreeWalker and then iterating over the nodes.

I'm getting the error:

Type 'Node | null' is not assignable to type 'Node'. Type 'null' is not assignable to type 'Node'.

When trying to use

currentNode = walker.nextNode();

const htmlString = marked(markdownString);
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const walker = document.createTreeWalker(doc, NodeFilter.SHOW_TEXT);

const textList: string[] = [];
let currentNode = walker.currentNode;

while (currentNode != null) {
    if (currentNode.textContent != null) {
        textList.push(currentNode.textContent);
    }
    if (walker.nextNode() != null) {
        currentNode = walker.nextNode();
    } else {
        break;
    }
}

I'm not sure why TypeScript is complaining about not being able to assign 'null' to 'currentNode' when I already have a check in place if nextNode() is null before entering the block to assign 'currentNode = walker.nextNode()'


Solution

  • Because each call to nextNode() might return a different value.

    To use the type guard (aka "narrowing"... your if statement) you'll need to use an intermediate variable that TypeScript can make reasonable assumptions about:

        const nextNode = walker.nextNode();
        if (nextNode != null) {
            currentNode = nextNode;
        } else {
            break;
        }
    
    

    Calling nextNode() twice was probably resulting in an undiscovered bug anyway as it was advancing your walker and thus skipping every other node.