How to resolve this parent: Element returning null?

I saw an old post that was never resolved and I am invested in it now.

Uncaught TypeError: Cannot read property ‘append’ of null in typescript

I tried reproducing it and I am also getting the error:

Uncaught TypeError: Cannot read property ‘append’ of null

export class UserForm {
  constructor(public parent: Element) {}

  template(): string {
    return `
        <div>
        <h1> User Form</h1>
        <input/>
        <div>
        `;

  }

  render(): void {
    const templateElement = document.createElement('template');
    templateElement.innerHTML = this.template();
    console.log(this.parent);
    this.parent.append(templateElement.content);
  }
}

this.parent console logs null for me as well. I thought perhaps it was because the DOM was not loading in time, but I tried this:

export class UserForm {
  // parent: Element;

  // constructor(parent: Element) {
  //   this.parent = parent;
  // }
  constructor(public parent: Element) {}

  template(): string {
    return `<div>
      <h1>User Form</h1>
      <input />
    </div>`;
  }

  render(): void {
    const templateElement = document.createElement("template");
    templateElement.innerHTML = this.template();
    window.addEventListener("DOMContentLoaded", (event) => {
      console.log("DOM fully loaded and parsed");
    });
    console.log(this.parent);
    this.parent.append(templateElement.content);
  }
}

And I got the console log of DOM fully loaded and parsed but this.parent is still null. If you do command + click for Element you get that Element is the most general base class from which all objects in a Document inherit.

Does anyone have any idea what is going on here?

So far, I believe this has something to do with the fact that you do not always find an Element in TypeScript, so you would get null instead, but if this is the case, how do we resolve that?

Answer

So it appears that the key to solving this is the not null assertion operator or what in the world of English grammar we know as the exclamation point.

Basically, you tell TypeScript to relax and stop yelling at you because you know what you are doing. Root constant will definitely reference Element. Otherwise, if the operator were to be omitted, root could refer to Element or null, if the element could not be found.

export class UserForm {
  constructor(public parent: Element) {}

  template(): string {
    return `<div>
      <h1>User Form</h1>
      <input />
    </div>`;
  }

  render(): void {
    const templateElement = document.createElement("template");
    templateElement.innerHTML = this.template();
    console.log(this.parent);

    this.parent.append(templateElement.content);
  }
}

Below would be the index.ts file:

import { UserForm } from "./views/UserForm";

const root: Element = document.getElementById("root")!;

const userForm = new UserForm(root);

userForm.render();

Below is the index.html:

<!DOCTYPE html>
<html>
  <body>
    <div id="root"></div>
    <script src="./src/index.ts"></script>
  </body>
</html>