Перейти к содержанию

Декораторы

Декораторы — это функции, которые можно использовать для декларативного аннотирования и изменения поведения классов.

Lit предоставляет набор дополнительных декораторов, которые позволяют использовать декларативные API для регистрации элементов, определения реактивных свойств и свойств запросов или добавления опций событий в методы обработчиков событий.

Например, декораторы @customElement и @property() позволяют компактно и декларативно зарегистрировать пользовательский элемент и определить реактивное свойство:

1
2
3
4
5
@customElement('my-element')
export class MyElement extends LitElement {
    @property()
    greeting = 'Welcome';
}

Lit поддерживает две различные версии предложения декораторов JavaScript — раннюю версию, поддерживаемую TypeScript, которую мы называем экспериментальными декораторами, и новую, окончательную версию, которую мы называем стандартными декораторами.

Между этими двумя предложениями есть небольшие различия в использовании (стандартные декораторы часто требуют ключевого слова accessor). Наши примеры кода написаны для экспериментальных декораторов, потому что мы рекомендуем их для производства в настоящее время.

Более подробную информацию смотрите в разделе Версии декораторов.

Встроенные декораторы

Декоратор Резюме Дополнительная информация
@customElement Определяет пользовательский элемент. Defining
@eventOptions Добавляет опции слушателя событий. События
@property Определяет публичное свойство. Properties
@state Определяет частное свойство состояния Properties
@query Определяет свойство, которое возвращает элемент в шаблоне компонента. Shadow DOM
@queryAll Определяет свойство, которое возвращает список элементов в шаблоне компонента. Shadow DOM
@queryAsync Определяет свойство, которое возвращает обещание, разрешающее элемент в шаблоне компонента. Shadow DOM
@queryAssignedElements Определяет свойство, которое возвращает дочерние элементы, назначенные определенному слоту. Shadow DOM
@queryAssignedNodes Определяет свойство, которое возвращает дочерние узлы, назначенные определенному слоту. Shadow DOM

Импорт декораторов

Вы можете импортировать все декораторы Lit через модуль lit/decorators.js:

1
2
3
4
5
6
import {
    customElement,
    property,
    eventOptions,
    query,
} from 'lit/decorators.js';

Чтобы сократить объем кода, необходимого для запуска компонента, декораторы можно импортировать в код компонента по отдельности. Все декораторы доступны по адресу lit/decorators/<decorator-name>.js. Например,

1
2
import { customElement } from 'lit/decorators/custom-element.js';
import { eventOptions } from 'lit/decorators/event-options.js';

Включение декораторов

Чтобы использовать декораторы, необходимо собрать код с помощью компилятора, например TypeScript или Babel.

В будущем, когда декораторы будут нативно поддерживаться в браузерах, в этом больше не будет необходимости

Использование декораторов в TypeScript

TypeScript поддерживает как экспериментальные, так и стандартные декораторы. Мы рекомендуем разработчикам TypeScript пока использовать экспериментальные декораторы для оптимального вывода компилятора. Если ваш проект требует использования стандартных декораторов или установки "useDefineForClassFields": true, перейдите к разделу миграция на стандартные декораторы.

Чтобы использовать экспериментальные декораторы, необходимо включить опцию компилятора experimentalDecorators.

Также необходимо убедиться, что параметр useDefineForClassFields имеет значение false. Это требуется только в том случае, если target установлен на ES2022 или выше, но рекомендуется явно установить значение false. Это необходимо для того, чтобы избежать проблем с полями классов при объявлении свойств.

1
2
3
4
5
6
7
// tsconfig.json
{
    "compilerOptions": {
        "experimentalDecorators": true,
        "useDefineForClassFields": false
    }
}

Включение emitDecoratorMetadata не требуется и не рекомендуется.

Миграция экспериментальных декораторов TypeScript в стандартные декораторы

Декораторы Lit разработаны для поддержки стандартного синтаксиса декораторов (с использованием accessor в декораторах полей классов) в режиме экспериментальных декораторов TypeScript.

Это позволяет постепенно переходить от экспериментальных декораторов, начиная с добавления ключевого слова accessor к декорированным свойствам без изменения поведения. Когда все декорированные поля класса будут использовать ключевое слово accessor, вы можете изменить опции компилятора, чтобы завершить переход на стандартные декораторы:

1
2
3
4
5
6
7
// tsconfig.json
{
    "compilerOptions": {
        "experimentalDecorators": false, // default for TypeScript 5.0 and up
        "useDefineForClassFields": true // default when "target" is "ES2022" or higher
    }
}

Примечание: Ключевое слово accessor появилось в TypeScript 4.9, а стандартные декораторы с метаданными требуют TypeScript ≥5.2.

Использование декораторов в Babel

Babel поддерживает стандартные декораторы с плагином @babel/plugin-proposal-decorators начиная с версии 7.23. Babel не поддерживает экспериментальные декораторы TypeScript, поэтому вы должны использовать декораторы Lit с стандартным синтаксисом декораторов, используя ключевое слово accessor для декорированных полей класса.

Включите декораторы, добавив @babel/plugin-proposal-decorators с этими настройками конфигурации Babel:

1
2
3
4
5
6
7
8
9
// babel.config.json
{
    "plugins": [
        [
            "@babel/plugin-proposal-decorators",
            { "version": "2023-05" }
        ]
    ]
}

Примечание: Декораторы Lit работают только с "версией": "2023-05". Другие версии, включая ранее поддерживаемую "2018-09", не поддерживаются.

Версии декораторов

Декораторы являются stage 3 proposal для добавления в стандарт ECMAScript. Такие компиляторы, как Babel и TypeScript, поддерживают декораторы, хотя ни в одном браузере они пока не реализованы. Декораторы Lit работают в Babel и TypeScript, и будут работать в браузерах, когда они реализуют их нативно.

Что означает этап 3?

Это означает, что текст спецификации завершен и готов к внедрению в браузеры. После того как спецификация будет реализована в нескольких браузерах, она может перейти на финальную стадию, стадию 4, и быть добавлена в стандарт ECMAScript. Предложение на стадии 3 будет изменено только в том случае, если в процессе реализации будут обнаружены критические проблемы.

Более ранние предложения по декораторам

До того как предложение TC39 достигло стадии 3, компиляторы реализовывали ранние версии спецификации декораторов.

Наиболее заметным из них является TypeScript's experimental decorators, который Lit поддерживал с момента своего появления и является нашей текущей рекомендацией к использованию.

Babel также поддерживал различные версии спецификации с течением времени, как видно из опции "version" плагина декораторов. В прошлом Лит 2 поддерживал версию "2018-09" для пользователей Babel, но теперь от нее отказались в пользу стандартной версии "2023-05", описанной ниже.

Стандартные декораторы

Стандартные декораторы — это версия декораторов, которая достигла 3-й стадии консенсуса в TC39, органе, определяющем ECMAScript/JavaScript.

Стандартные декораторы поддерживаются в TypeScript и Babel, а в ближайшем будущем появятся и в родном браузере.

Самое большое отличие стандартных декораторов от экспериментальных заключается в том, что по соображениям производительности стандартные декораторы не могут изменять вид декорируемого и заменяемого члена класса — поля, аксессоры и методы — и будут создавать только член того же типа.

Поскольку многие декораторы Lit генерируют аксессоры, это означает, что декораторы нужно применять к аксессорам, а не к полям класса.

Чтобы сделать это удобным, стандартная спецификация декораторов добавляет ключевое слово accessor для объявления "автоаксессоров":

1
2
3
class MyClass {
    accessor foo = 42;
}

Автоаксессоры создают пару геттеров и сеттеров, которые считывают и записывают данные из приватного поля. Декораторы могут обернуть эти геттеры и сеттеры.

Декораторы Lit, работающие с полями класса с экспериментальными декораторами — такими как @property(), @state(), @query() и др. — должны применяться к аксессорам или автоаксессорам со стандартными декораторами:

1
2
3
4
5
@customElement('my-element')
export class MyElement extends LitElement {
    @property()
    accessor greeting = 'Welcome';
}

Соображения по поводу вывода компилятора

Вывод компилятора для стандартных декораторов, к сожалению, велик из-за необходимости генерировать аксессоры, приватные хранилища и другие объекты, которые являются частью API декораторов.

Поэтому мы рекомендуем пользователям, желающим использовать декораторы, по возможности пока использовать экспериментальные декораторы TypeScript.

В будущем команда Lit планирует добавить преобразования декораторов в наш дополнительный компилятор Lit Compiler, чтобы компилировать стандартные декораторы в более компактный вывод компилятора. Поддержка нативных браузеров также устранит необходимость в каких-либо преобразованиях компилятора.

Комментарии