Дженерики

FAST Element — это современный фреймворк для создания веб-компонентов с декларативным синтаксисом и реактивной моделью данных. В JavaScript дженерики применяются чаще всего при работе с TypeScript, который используется вместе с FAST для обеспечения строгой типизации и переиспользуемости компонентов.

Типизация компонентов

Каждый компонент FAST Element определяется через класс, наследующий FASTElement, и сопровождается шаблоном (html template). Для дженериков важно правильно указать типы свойств, методов и событий, чтобы обеспечивать безопасность типов при переиспользовании компонента.

Пример базового компонента с дженериком:

import { FASTElement, html, css, customElement, attr } from "@microsoft/fast-element";

const template = html<MyComponent<any>>`
  <div>
    <span>${x => x.value}</span>
  </div>
`;

@customElement({ name: "my-component", template })
export class MyComponent<T> extends FASTElement {
  @attr value!: T;
}

В этом примере MyComponent принимает дженерик T, который задаёт тип свойства value. Это позволяет при использовании компонента указывать любой тип данных — строку, число, объект или массив.

Дженерики в реактивных свойствах

FAST Element предоставляет декораторы @attr и @observable для реактивных свойств. С дженериками их можно сочетать для строгой типизации данных:

import { observable } from "@microsoft/fast-element";

export class ListComponent<T> extends FASTElement {
  @observable items: T[] = [];

  addItem(item: T) {
    this.items = [...this.items, item];
  }
}

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

Дженерики в методах компонента

Методы компонентов также могут быть дженериками, что позволяет работать с различными типами данных без дублирования кода:

export class TableComponent<T> extends FASTElement {
  rows: T[] = [];

  filter<U extends keyof T>(key: U, value: T[U]): T[] {
    return this.rows.filter(row => row[key] === value);
  }
}

Метод filter принимает ключ свойства U объекта типа T и значение этого свойства. Использование дженериков гарантирует, что ключи и значения соответствуют структуре объекта, предотвращая ошибки во время компиляции.

Дженерики и события

FAST Element поддерживает типизацию событий через кастомные события (CustomEvent). Дженерики позволяют точно определить тип передаваемых данных:

export class SelectComponent<T> extends FASTElement {
  select(item: T) {
    this.$emit("item-selected", item);
  }

  $emit<K extends string, D>(type: K, detail: D) {
    this.dispatchEvent(new CustomEvent(type, { detail }));
  }
}

Использование дженериков здесь гарантирует, что detail события соответствует ожидаемому типу T, что повышает безопасность при подписке на события в родительских компонентах.

Комбинация дженериков и интерфейсов

Интерфейсы часто используются вместе с дженериками для описания сложных структур данных:

interface User {
  id: number;
  name: string;
}

export class UserListComponent extends FASTElement {
  @observable users: User[] = [];

  addUser(user: User) {
    this.users.push(user);
  }
}

Если компонент должен быть универсальным, дженерик позволяет заменить User на любой другой тип:

export class GenericListComponent<T> extends FASTElement {
  @observable items: T[] = [];

  addItem(item: T) {
    this.items.push(item);
  }
}

Это создаёт универсальный, переиспользуемый компонент, полностью совместимый с TypeScript.

Ограничения дженериков

При использовании дженериков важно помнить:

  • Дженерики не могут использоваться напрямую в шаблонах HTML для динамической генерации типов. Они работают только на уровне TypeScript.
  • Не рекомендуется усложнять дженерики несколькими уровнями наследования в компонентах, так как это усложняет понимание кода.
  • Типизация событий через дженерики требует точного определения интерфейсов данных, иначе TS может не подхватывать типы корректно.

Применение дженериков в проектах FAST

Дженерики позволяют создавать универсальные и типобезопасные компоненты, что особенно важно при работе с крупными приложениями. Использование дженериков в FAST Element повышает переиспользуемость кода, упрощает тестирование и интеграцию, а также обеспечивает строгую проверку типов на этапе компиляции TypeScript.

Типичные сценарии применения:

  • Универсальные списки (ListComponent<T>), таблицы (TableComponent<T>) и селекты (SelectComponent<T>).
  • Методы для фильтрации, сортировки и трансформации данных с гарантией правильных типов.
  • Типизация пользовательских событий и их payload для безопасного взаимодействия между компонентами.

Строгое применение дженериков в сочетании с реактивной моделью FAST Element позволяет создавать масштабируемые и поддерживаемые интерфейсы с полной поддержкой TypeScript.