Home > Blockchain >  How to get Literal instead of Union type in TypeScript
How to get Literal instead of Union type in TypeScript

Time:12-25

I created a function for creating dynamic element. But instead of returning the literal type of the element it is returning the union of <HTMLElementTagNameMap>.

function createElement(type: keyof HTMLElementTagNameMap) {
  return document.createElement(type)
}

If we just use the above function it is returning the Union of :

(HTMLElement | HTMLObjectElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | ... 57 more ... | HTMLVideoElement).

What I have tried so far :

type valueOf<T> = T[keyof T]

function createElement<T extends valueOf<HTMLElementTagNameMap>>(type: keyof HTMLElementTagNameMap) {
  return document.createElement(type) as T
}

P.S - I am also quite confused! How'd the above function worked?

but instead using the above function in the way like mentioned below :

const div = createElement<HTMLDivElement>('div')

I want it to infer automatically the type of type like it does when we use :

let li = document.createElement('li')

CodePudding user response:

The code works because you're passing the return type manually by the generic type T.

you can automate that by the code below:

const createElement = <K extends keyof HTMLElementTagNameMap>(name: K): HTMLElementTagNameMap[K]{
  return document.createElement(name)
}

const div = createElement('div')
console.log(div)
// [LOG]: HTMLDivElement: {} 

it's not so different than the one you've written. I hope it helped. if you have any questions you are welcome to ask in comments

CodePudding user response:

If you want the same behaviour as document.createElement you can write simply

function createElement<K extends keyof HTMLElementTagNameMap>(type: K) {
  return document.createElement(type);
}

or if you want to pick tag name by HTML element, you can use something like this

type PickTagNameForHTMLElement<TargetElement> = {
  [K in keyof HTMLElementTagNameMap]: HTMLElementTagNameMap[K] extends TargetElement ? K : never;
}[keyof HTMLElementTagNameMap];

function createElement<TargetElement extends HTMLElement>(type: PickTagNameForHTMLElement<TargetElement>) {
  return document.createElement(type);
}
  • Related