Generic Component Declarations
I was creating some custom elements from a generic base class using LitElement and came to some odd problems where the analyzer didn't type-check generic-related properties.
A simplified version of what I was doing:
export class GenericElement<T> extends LitElement {
@property() key!: keyof T
}
declare global {
interface HTMLElementTagNameMap {
'generic-specific': GenericElement<{ id: number, name: string }>
}
}
First I tried to do it the vanilla way and type checking works fine:
const element = document.createElement('generic-specific')
element.key = 'what' // ✅ TS2322: Type '"what"' is not assignable to type '"id" | "name"'.
However, for some reason, it doesn't work in tagged html templates:
export const someTemplate = () => html`
<!-- ❌ Not type-checked -->
<generic-specific key='what??'></generic-specific>
`
I guess the analyzer doesn't analyze the declared generic part in the HTMLElementTagNameMap? because it thinks the key is of type keyof T instead of keyof { id: number, name: string }.
Would be glad to know what I'm missing or to know if there are work-arounds for now. Also, if these generic declarations cannot be supported due to some TypeScript API limitations, would it make sense to disable these checks for now?
Anybody knows workarounds inside of html tagged templates that verify the type checks? The only one I could find is:
export function pwSelectInput<T, Q extends keyof T>(props: Pick<PwSelectInput<T, Q>, "onchange" | "disabled" | "initial" | "label" | "name" | "options" | "task">) {
const {
onchange,
disabled,
initial,
label,
name,
options,
task,
...rest
} = props;
const _: {} = rest;
return html`<pw-select-input
?disabled=${disabled}
@change=${onchange}
label=${label}
.name=${name}
.options=${options}
.task=${task}
.initial=${initial}
></pw-select-input>`;
}
which I think is super ugly but it seems to work.
And how realistic is it that this gets implemented natively?