Skip to content

Instantly share code, notes, and snippets.

@StoneyEagle
Created August 8, 2024 11:04
Show Gist options
  • Save StoneyEagle/5df834788300bd403d9a203b33ed8467 to your computer and use it in GitHub Desktop.
Save StoneyEagle/5df834788300bd403d9a203b33ed8467 to your computer and use it in GitHub Desktop.
Typesafe create element
/**
* Creates a new HTML element of the specified type and assigns the given ID to it.
* @param type - The type of the HTML element to create.
* @param id - The ID to assign to the new element.
* @param unique - Whether to use an existing element with the specified ID if it already exists.
* @returns An object with four methods:
* - `addClasses`: Adds the specified CSS class names to the element's class list and returns the next 3 functions.
* - `appendTo`: Appends the element to a parent element and returns the element.
* - `prependTo`: Prepends the element to a parent element and returns the element.
* - `get`:Returns the element.
*/
const createElement = <K extends keyof HTMLElementTagNameMap>(type: K, id: string, unique?: boolean) =>{
let el: HTMLElementTagNameMap[K];
if (unique) {
el = (document.getElementById(id) ?? document.createElement(type)) as HTMLElementTagNameMap[K];
} else {
el = document.createElement(type);
}
el.id = id;
return {
addClasses: (names: string[]) => addClasses(el, names),
appendTo: <T extends Element>(parent: T) => {
parent.appendChild(el);
return el;
},
prependTo: <T extends Element>(parent: T) => {
parent.prepend(el);
return el;
},
get: () => el,
};
}
/**
* Adds the specified CSS class names to the given element's class list.
*
* @param el - The element to add the classes to.
* @param names - An array of CSS class names to add.
* @returns An object with three methods:
* - `appendTo`: Appends the element to a parent element and returns the element.
* - `prependTo`: Prepends the element to a parent element and returns the element.
* - `get`:Returns the element.
* @template T - The type of the element.
*/
const addClasses = <T extends Element>(el: T, names: string[]) => {
for (const name of names.filter(Boolean)) {
el.classList?.add(name.trim());
}
return {
appendTo: <T extends Element>(parent: T) => {
parent.appendChild(el);
return el;
},
prependTo: <T extends Element>(parent: T) => {
parent.prepend(el);
return el;
},
get: () => el,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment