Lit полностью совместим с TypeScript, что позволяет создавать высоко типизированные веб-компоненты. TypeScript обеспечивает статическую проверку типов, автодополнение и поддержку современных возможностей ECMAScript, делая разработку компонентов более безопасной и предсказуемой.
Для начала работы с TypeScript достаточно установить необходимые зависимости и настроить компилятор:
npm install --save lit
npm install --save-dev typescript
Создаётся файл tsconfig.json, где важно указать
следующие ключевые опции:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Node",
"lib": ["DOM", "ES2022"],
"strict": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true
}
}
Опции experimentalDecorators и
emitDecoratorMetadata нужны для работы с декораторами Lit,
такими как @property.
Lit предоставляет декоратор @property, который позволяет
описывать свойства веб-компонента. TypeScript усиливает его
возможностями строгой типизации:
import { LitElement, html, css } from 'lit';
import { property } from 'lit/decorators.js';
class MyComponent extends LitElement {
@property({ type: String })
name: string = 'Lit';
@property({ type: Number })
count: number = 0;
@property({ type: Boolean })
visible: boolean = true;
render() {
return html`
<div ?hidden=${!this.visible}>
${this.name}: ${this.count}
</div>
`;
}
}
customElements.define('my-component', MyComponent);
Ключевые моменты:
type в @property используется для
конвертации значений атрибутов HTML в нужный тип.string, number, boolean),
предотвращая ошибки при присваивании.Lit поддерживает генерацию кастомных событий через метод
dispatchEvent. С TypeScript можно описать типы события,
чтобы упростить работу с слушателями:
class MyComponent extends LitElement {
private _count: number = 0;
increment() {
this._count++;
this.dispatchEvent(new CustomEvent<'increment' | 'change'>('change', {
detail: { count: this._count }
}));
}
}
При использовании с TypeScript можно создавать интерфейсы для
detail событий:
interface CountChangeDetail {
count: number;
}
this.dispatchEvent(new CustomEvent<CountChangeDetail>('change', {
detail: { count: this._count }
}));
Это позволяет при обработке события точно знать структуру
event.detail:
element.addEventListener('change', (event) => {
const detail = (event as CustomEvent<CountChangeDetail>).detail;
console.log(detail.count);
});
Lit использует HTML-шаблоны через функцию html. Для
строгой типизации можно определить интерфейсы для структуры данных,
которая рендерится:
interface User {
id: number;
name: string;
}
class UserList extends LitElement {
@property({ type: Array })
users: User[] = [];
render() {
return html`
<ul>
${this.users.map(user => html`<li>${user.name}</li>`)}
</ul>
`;
}
}
TypeScript позволяет следить, чтобы users всегда был
массивом объектов с нужными полями. Любая попытка передать другой тип
вызовет ошибку на этапе компиляции.
Lit поддерживает реактивные свойства через геттеры и сеттеры. TypeScript обеспечивает строгий контроль типов:
class CounterElement extends LitElement {
private _count = 0;
@property({ type: Number })
get count(): number {
return this._count;
}
set count(value: number) {
const oldValue = this._count;
this._count = value;
this.requestUpdate('count', oldValue);
}
}
requestUpdate позволяет вручную
инициировать обновление при изменении внутреннего состояния.Для более сложных компонентов можно применять обобщения TypeScript, обеспечивая типовую гибкость:
class DataList<T> extends LitElement {
@property({ type: Array })
items: T[] = [];
render() {
return html`
<ul>
${this.items.map(item => html`<li>${JSON.stringify(item)}</li>`)}
</ul>
`;
}
}
interface Product {
id: number;
title: string;
}
const productList = new DataList<Product>();
productList.items = [{ id: 1, title: 'Laptop' }];
Обобщения позволяют создавать универсальные компоненты, которые строго типизированы, но при этом остаются гибкими для разных данных.
Декораторы @property, @state,
@query и @queryAll полностью поддерживают
TypeScript, что позволяет использовать автодополнение и проверку типов
даже для внутренних состояний и элементов DOM:
import { state, query } from 'lit/decorators.js';
class InputComponent extends LitElement {
@state()
private value: string = '';
@query('input')
private inputElement!: HTMLInputElement;
updateValue() {
this.value = this.inputElement.value;
}
}
@state() помечает внутреннее состояние, которое не
отражается в атрибутах HTML.@query() возвращает строго типизированный
DOM-элемент.TypeScript в связке с Lit превращает веб-компоненты из простых блоков интерфейса в мощные, масштабируемые и безопасные элементы фронтенда.