typescriptchild-nodes

Typescript ChildNode: `parentElement` and/or `parentNode` is null?


So here is a philosophical question.

In TypeScript a ChildNode can be parentless, since both ChildNode.parentElement and ChildNode.parentNode have a null type option.

But being ChildNode wouldn't it, by the nature of it, have a parent? I can understand that parentElement might be null, since it might derive from a non element node (or would that even be possible) but shouldn't at least parentNode be non-null?

I understand that it is not really specifically indicated in the DOM spec, but wouldn't it be strange to have a ChildNode with no parent?

Is it like this in the case that you might move the node away from the parent? But wouldn't something like this change the type of the ChildNode, to plain ol' Node?

I would be really interested in having your insight on this question, as it has left me a bit puzzled.


Solution

  • From https://developer.mozilla.org/en-US/docs/Web/API/ChildNode:

    The ChildNode mixin contains methods and properties that are common to all types of Node objects that can have a parent. It's implemented by Element, DocumentType, and CharacterData objects.

    ChildNode does not mean "this node currently has a parent node". It's just a mixin that other types implement to include the remove(), before(), after(), and replaceWith() methods.

    An example of a type that inherits from Node but does not mix in the ChildNode methods is Document. A Document is a Node (its children's parentNode would be itself) but it can never have a parent node, so document.remove() produces a compilation error.

    Is it like this in the case that you might move the node away from the parent? But wouldn't something like this change the type of the ChildNode, to plain ol' Node?

    This isn't how TypeScript's static type checking works — calling a method such as remove() on an object doesn't change its type. (It might be technically possible in JavaScript to change an object's prototype, but TypeScript doesn't model this.) The node is still an object of the same class it was before removal, so it still implements these methods, even though calling them when the node has no parent might not make sense. And in fact, since every Element is a ChildNode, dynamically changing the type after element.remove() wouldn't make sense because the element should still be an Element.