I am trying to create a HTMLHeadingElement
. To do that I use:
const myHeading: HTMLHeadingElement = document.createElement("h3");
So this works perfectly. But when I try to create this element more dynamically, I fail doing so:
const level: number = 3;
const headingLevel: string = "h" + level;
const myHeading: HTMLHeadingElement = document.createElement(headingLevel);
So, it looks like essentially the same thing, but apparently it isn't. The error I get when hovering myHeading
is:
Type 'HTMLElement' is not assignable to type 'HTMLHeadingElement'
In the first example, though, the method createElement("h3")
right away returns the type HTMLHeadingElement
.
Now, my first question is, how are these two commands different? And if not clear then, how can I get the same result within myHeading
in the second example as shown in the first example?
TypeScript has many overloads for createElement()
in its lib.dom.d.ts
file, so it knows that when createElement()
is called with 'h3', that will return an HTMLHeadingElement:
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K];
createElement(tagName: string): HTMLElement;
When it doesn't know the tag name at compile time, all it knows is that the method returns an HTMLElement. You know that, however, so you can tell TypeScript:
const myHeading = document.createElement(headingLevel) as HTMLHeadingElement;
headingLevel
is declared to have type string
. That means it can be any string, including, say, "canvas"
, which would not lead to myHeading
being a HTMLHeadingElement
.
You need to be more specific with your types.
const headingLevel: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
Unfortunately, it appears TypeScript will not let you make these as follows
const level: 1 | 2 | 3 | 4 | 5 | 6
// TypeScript's types don't know how literals are concatenated
const headingLevel: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" = "h" + level
So you'd need to transform level
into its corresponding tag name using a dictionary or array or similar.
const LEVEL_MAP: {1: "h1", 2: "h2", 3: "h3", 4: "h4", 5: "h5", 6: "h6"} = {
1: "h1",
2: "h2",
3: "h3",
4: "h4",
5: "h5",
6: "h6",
}
const headingLevel: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" = LEVEL_MAP[level]
... It would be nice if TypeScript supported "h" + 1
being of type "h1"
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With