TypeScript и Composition API

Vue.js начиная с версии 3 предоставляет мощный инструмент для разработки компонентов — Composition API, который в сочетании с TypeScript обеспечивает строгую типизацию и улучшает читаемость кода. Composition API позволяет организовать логику компонентов в виде функций, что облегчает повторное использование кода и масштабирование приложений.


Основы Composition API с TypeScript

В основе Composition API лежит функция setup, которая вызывается перед рендерингом компонента и возвращает объект, содержащий реактивные данные, методы и вычисляемые свойства. В TypeScript важно явно указывать типы для реактивных данных и функций.

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

import { ref, computed } from 'vue';

export default {
  setup() {
    const count = ref<number>(0); // реактивная переменная с типом number

    const doubleCount = computed<number>(() => count.value * 2); // вычисляемое свойство с типом number

    function increment(): void {
      count.value++;
    }

    return { count, doubleCount, increment };
  }
}

Ключевые моменты:

  • ref<T>() создаёт реактивное значение с явным типом T.
  • computed<T>() создаёт вычисляемое свойство с указанным типом.
  • Все функции внутри setup можно типизировать так же, как обычные TypeScript функции.

Типизация Props и Emits

Composition API позволяет строго типизировать props и events, что особенно важно в больших приложениях.

Props:

import { defineComponent } from 'vue';

export default defineComponent({
  props: {
    title: {
      type: String,
      required: true
    },
    count: {
      type: Number,
      default: 0
    }
  },
  setup(props) {
    const titleLength: number = props.title.length;
    return { titleLength };
  }
});

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

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

export default defineComponent({
  props: {
    user: {
      type: Object as () => User,
      required: true
    }
  },
  setup(props) {
    const userName: string = props.user.name;
    return { userName };
  }
});

Emits:

События можно типизировать с помощью defineEmits:

const emit = defineEmits<{
  (e: 'update', value: number): void;
  (e: 'delete', id: string): void;
}>();

function updateValue(newValue: number) {
  emit('update', newValue);
}

Типизация emit позволяет избежать ошибок при вызове событий и обеспечивает автодополнение в редакторе.


Реактивные объекты и ref vs reactive

В Composition API есть два способа создания реактивного состояния: ref и reactive.

ref создаёт примитив или объект, к которому можно обращаться через .value:

const message = ref<string>('Hello');
message.value = 'Hi';

reactive создаёт реактивный объект, где доступ к свойствам осуществляется напрямую:

import { reactive } from 'vue';

interface State {
  count: number;
  text: string;
}

const state = reactive<State>({
  count: 0,
  text: 'Hello'
});

state.count++;
state.text = 'Hi';

Важно помнить: для примитивов лучше использовать ref, для объектов и массивов — reactive.


Computed и Watch с TypeScript

Computed свойства позволяют создавать производные значения на основе реактивного состояния:

const fullName = computed<string>(() => `${state.firstName} ${state.lastName}`);

Watch используется для реакции на изменения состояния:

import { watch } from 'vue';

watch(() => state.count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldValue} to ${newValue}`);
});

Типизация обеспечивает строгий контроль типов, особенно при сложных структурах состояния.


Комбинирование Composition API с TypeScript и Vue Router / Vuex

При интеграции с Vue Router и Vuex TypeScript позволяет типизировать параметры маршрутов и состояния хранилища:

import { useRoute } from 'vue-router';
import { useStore } from 'vuex';

const route = useRoute();
const store = useStore<{ count: number }>();

const id: string = route.params.id as string;
const currentCount: number = store.state.count;

Такой подход предотвращает ошибки при обращении к параметрам маршрута или состоянию хранилища.


Советы по организации кода

  • Разделять логические блоки на отдельные функции для повторного использования.
  • Использовать интерфейсы и типы для props, состояния и событий.
  • Предпочитать ref для примитивов и reactive для объектов.
  • Типизировать функции, возвращаемые из setup, чтобы сохранить автодополнение и строгую проверку типов.

Composition API с TypeScript делает код более предсказуемым, сокращает количество ошибок во время разработки и улучшает поддержку крупных проектов Vue.js.