Typed Components
On every build, Stencil writes src/components.d.ts with types for each of your components. For a my-toggle component, it declares:
HTMLMyToggleElement: the element, with its props and methods. It's global, likeHTMLButtonElement, so it needs no import.MyToggleCustomEvent<T>: the type of the component's events.- JSX types, so
<my-toggle>is type-checked wherever you render it.
Referencing Elements
Use the HTML{Tag}Element interfaces wherever you hold a component element:
@Element() el: HTMLMyPanelElement;
private toggle?: HTMLMyToggleElement;
render() {
return <my-toggle ref={(el) => (this.toggle = el)} />;
}
querySelector() returns the right interface for a tag name on its own, so its props and methods are typed:
const toggle = this.el.querySelector('my-toggle'); // HTMLMyToggleElement | null
toggle?.toggle();
Typed Events
An event's type comes from its @Event() declaration. Here my-toggle declares that its myChange event's detail has a checked boolean:
@Event() myChange: EventEmitter<{ checked: boolean }>;
Event handlers in JSX are then typed from that detail:
<my-toggle onMyChange={(ev) => (this.open = ev.detail.checked)} />
To type a handler declared elsewhere, import the event type from components.d.ts:
import { MyToggleCustomEvent } from '../../components';
private onChange = (ev: MyToggleCustomEvent<{ checked: boolean }>) => {
this.open = ev.detail.checked;
};
addEventListener() on a component element is typed the same way.
Type-Checked JSX
Rendering one of your components in another component's render() checks its props: a wrong type, or a missing required prop, is a compile error:
<my-toggle checked="yes" /> // Type 'string' is not assignable to type 'boolean'
In Tests
The same interfaces type elements in tests. In a Playwright test, for example:
await page.locator('my-toggle').evaluate((el: HTMLMyToggleElement) => (el.checked = true));
For Consumers
components.d.ts is for your own project. What consumers get comes from other outputs:
- The
typesoutput target publishes the same types indist/types, for consumers using TypeScript. See Editor Support for how their apps pick them up. - Framework Types make your tags type-checked in React, Vue, Solid, Svelte, and Preact templates.
- The React, Vue, and Angular wrappers give consumers typed framework components.
Committing components.d.ts
Stencil regenerates the file on every build, so committing it is optional:
- Committed, types work straight after cloning, before the first build, and a pull request's diff shows changes to your components' public API.
- Ignored (add it to
.gitignore), there's no generated file to keep in sync or resolve conflicts in. Editors show missing types on a fresh clone until the first build.