TypeScript

@beforesemicolon/web-component is designed with first-class TypeScript support, offering complete type safety for properties, internal state, reference bindings, and custom element interfaces.

Subclassing with Generics

The WebComponent base class accepts two optional generic parameters: Props and State.

typescript
1import { WebComponent, html } from '@beforesemicolon/web-component'2 3// 1. Define your component's types4interface ButtonProps {5    label: string6    disabled: boolean7}8 9interface ButtonState {10    clickCount: number11}12 13// 2. Pass them to the WebComponent class14class CustomButton extends WebComponent<ButtonProps, ButtonState> {15    static observedAttributes = ['label', 'disabled']16 17    // Provide default props values as class properties18    label = 'Click me'19    disabled = false20 21    // Provide initial state22    initialState = {23        clickCount: 0,24    }25 26    handleClick = () => {27        this.setState((prev) => ({ clickCount: prev.clickCount + 1 }))28    }29 30    render() {31        // Both this.props and this.state are fully typed!32        return html`33            <button34                onclick="${this.handleClick}"35                disabled="${this.props.disabled}"36            >37                ${() => this.props.label()} (${() => this.state.clickCount()})38            </button>39        `40    }41}

Custom Element References

When working with DOM APIs or template references, you often need a reference type that contains both the custom properties of your element and the standard WebComponent / HTMLElement APIs.

The HTMLComponentElement<Props> utility type provides this capability. It combines the WebComponent class with your custom property signatures (without requiring getters) so you can directly read or write values.

typescript
1import { HTMLComponentElement } from '@beforesemicolon/web-component'2 3// Given the CustomButton defined above:4type CustomButtonElement = HTMLComponentElement<ButtonProps>5 6// Now you can safely interact with the reference:7const myButton = document.querySelector<CustomButtonElement>('custom-button')8 9if (myButton) {10    // Directly access or update props on the instance11    myButton.label = 'Submit Form'12    myButton.disabled = true13 14    // Standard HTMLElement / WebComponent methods are also available15    myButton.dispatch('custom-event', { detail: 'clicked' })16}

Exported Utility Types

The following TypeScript utility types are exported from the library to help build typed component-based architectures:

ObjectInterface<P>

Constraints checking helper representing an object containing key-value pairs where keys must be string, number, or symbol.

typescript
1type ObjectInterface<P> = {2    [K in keyof P & (string | symbol | number)]: P[K]3}

Props<P>

Maps each key in a properties interface P to a reactive StateGetter from @beforesemicolon/markup. This matches the type of this.props.

typescript
1type Props<P> = {2    [K in keyof P]: StateGetter<P[K]>3}

PropsSetters<P>

Maps each key in a properties interface P to a reactive StateSetter from @beforesemicolon/markup.

typescript
1type PropsSetters<P> = {2    [K in keyof P]: StateSetter<P[K]>3}

State<S>

Maps each key in a state interface S to a reactive StateGetter from @beforesemicolon/markup. This matches the type of this.state.

typescript
1type State<S> = {2    [K in keyof S]: StateGetter<S[K]>3}

StateSetters<S>

Maps each key in a state interface S to a reactive StateSetter from @beforesemicolon/markup.

typescript
1type StateSetters<S> = {2    [K in keyof S]: StateSetter<S[K]>3}
edit this doc