Last active
September 21, 2023 02:25
-
-
Save difosfor/ceeb01d03a8db7dc68d5cd4167d60637 to your computer and use it in GitHub Desktop.
Typed LitElement events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { customElement, LitElement } from 'lit-element'; | |
type UnpackCustomEvent<T> = T extends CustomEvent<infer U> ? U : never; | |
// Define custom event types and details here | |
interface CustomEventMap { | |
/** | |
* Dispatched when an error occurs. | |
*/ | |
'my-error': CustomEvent<{ error: Error }>; | |
/** | |
* Dispatched when initialized. | |
*/ | |
'my-initialized': CustomEvent<{}>; | |
} | |
interface CombinedEventMap extends HTMLElementEventMap, CustomEventMap {} | |
// Add strict event type support to addEventListener etc. | |
interface MyElement { | |
addEventListener<K extends keyof CombinedEventMap>( | |
type: K, | |
listener: (this: MyElement, ev: CombinedEventMap[K]) => void, | |
options?: boolean | AddEventListenerOptions, | |
): void; | |
removeEventListener<K extends keyof CombinedEventMap>( | |
type: K, | |
listener: (this: MyElement, ev: CombinedEventMap[K]) => void, | |
options?: boolean | EventListenerOptions, | |
): void; | |
} | |
// Add custom element to TypeScript's map (defined by @customElement below) | |
declare global { | |
interface HTMLElementTagNameMap { | |
'my-element': MyElement; | |
} | |
} | |
/** | |
* MyElement class is defined as `<my-element>`. | |
* | |
* @fires my-error - Dispatched with `detail.error: Error` when an error occurs. | |
* @fires my-initialized - Dispatched when initialized. | |
*/ | |
@customElement('my-element') | |
class MyElement extends LitElement { | |
/** | |
* A strict alternative to dispatchEvent for dispatching this element's custom events. | |
* | |
* @param type Custom event type | |
* @param detail Custom event detail | |
*/ | |
private dispatch<K extends keyof CustomEventMap>( | |
type: K, | |
detail: UnpackCustomEvent<CustomEventMap[K]>, | |
) { | |
return this.dispatchEvent(new CustomEvent(type, { detail })); | |
} | |
public connectedCallback() { | |
if (super.connectedCallback) { | |
super.connectedCallback(); | |
} | |
Promise.resolve().then( | |
() => this.dispatch('my-initialized', {}), | |
error => this.dispatch('my-error', { error }), | |
); | |
} | |
} | |
export default MyElement; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { html } from 'lit-element'; | |
import './my-element.ts'; | |
function onInitialized() { | |
console.log('Initialized!'); | |
} | |
function onError({ detail: { error } }: { detail: { error: Error } }) { | |
console.error(error); | |
} | |
// Using createElement: full typing support | |
const el = document.createElement('my-element'); | |
el.addEventListener('my-initialized', onInitialized); | |
el.addEventListener('my-error', onError); | |
// Using lit-html; in VS Code with lit-plugin: event-type name completion, but listener type not validated | |
const foo = html`<my-element @my-initialized=${onInitialized} @my-error=${onError}></my-element>`; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This provides strictly typed listening and dispatching support to a custom LitElement.