refactor: type element attributes

use attributes of html element type.

so that the following example is correctly typed:

elem('input', {
  className: 'foo',
  hidden: false,
  onclick: () => alert('hi'),
  tabIndex: 1,
  valueAsNumber: 1,
});

but this fails as foo is no valid attribute on div element:

elem('div', {foo: 'bar'});
pull/72/head
OFF0 2 years ago
parent 489a260427
commit 6e404eac6b
Signed by: offbyn
GPG Key ID: 94A2F643C51F37FA

@ -1,11 +1,11 @@
type Attributes = { type DataAttributes = {
[key: string]: string | number; data: {
} & {
data?: {
[key: string]: string | number; [key: string]: string | number;
} }
}; };
type Attributes<Type> = Partial<Type & DataAttributes>;
/** /**
* example usage: * example usage:
* *
@ -15,31 +15,43 @@ type Attributes = {
* *
* @param {string} name * @param {string} name
* @param {HTMLElement.prototype} props * @param {HTMLElement.prototype} props
* @param {Array<HTMLElement|string>} children * @param {Array<Node> | string | number} children
* @return HTMLElement * @return HTMLElement
*/ */
export const elem = <Name extends keyof HTMLElementTagNameMap>( export const elem = <Name extends keyof HTMLElementTagNameMap>(
name: Extract<Name, keyof HTMLElementTagNameMap>, name: Extract<Name, keyof HTMLElementTagNameMap>,
attrs: Attributes = {}, // TODO optional attrs?: Attributes<HTMLElementTagNameMap[Name]>,
children: Array<Node> | string = [], // TODO optional children?: Array<HTMLElement | string> | string | number,
): HTMLElementTagNameMap[Name] => { ): HTMLElementTagNameMap[Name] => {
const {data, ...props} = attrs;
const el = document.createElement(name); const el = document.createElement(name);
if (attrs) {
const {data, ...props} = attrs;
Object.assign(el, props); Object.assign(el, props);
if (data) {
Object.entries(data).forEach(([key, value]) => {
el.dataset[key] = value as string;
});
}
}
if (children != null) {
if (Array.isArray(children)) { if (Array.isArray(children)) {
el.append(...children); el.append(...children);
} else { } else {
const childType = typeof children; switch (typeof children) {
if (childType === 'number' || childType === 'string') { case 'number':
el.append(`${children}`);
break;
case 'string':
el.append(children); el.append(children);
} else { break;
console.error('call me'); default:
if (children instanceof Element) {
el.append(children);
break;
}
console.error(`expected element, string or number but got ${typeof children}`, children);
} }
} }
if (data) {
Object.entries(data).forEach(([key, value]) => {
el.dataset[key] = value as string;
});
} }
return el; return el;
}; };

Loading…
Cancel
Save