Эта статья — перевод оригинальной статьи «Announcing Vue 3.3«
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
Сегодня мы рады объявить о релизе Vue 3.3 «Rurouni Kenshin»!
Этот выпуск сосредоточен на улучшении опыта разработки — в частности, на использовании SFC <script setup> с TypeScript. Вместе с релизом 1.6 Vue Language Tools (ранее известного как Volar) мы решили многие давние проблемы при использовании Vue с TypeScript.
В этом посте представлен обзор основных возможностей версии 3.3. Для получения полного списка изменений, пожалуйста, ознакомьтесь с полным журналом изменений на GitHub.
<script setup> + Улучшения TypeScript DX
Поддержка импортированных и сложных типов в макросах
Ранее типы, используемые в параметре типа в defineProps и defineEmits, были ограничены локальными типами и поддерживали только литералы типов и интерфейсы. Это связано с тем, что Vue должен иметь возможность анализировать свойства интерфейса props для генерации соответствующих опций во время выполнения.
Теперь это ограничение устранено в версии 3.3. Компилятор теперь может разрешать импортированные типы и поддерживает ограниченный набор сложных типов:
<script setup lang="ts"> import type { Props } from './foo' // imported + intersection type defineProps<Props & { extraProp?: string }>() </script>
Обратите внимание, что поддержка сложных типов основана на AST и поэтому не является на 100% полной. Некоторые сложные типы, требующие фактического анализа типа, например, условные типы, не поддерживаются. Вы можете использовать условные типы для определения типа отдельного параметра, но не всего объекта параметров.
Подробнее: PR#8083
Обобщенные компоненты
Компоненты, использующие <script setup>, теперь могут принимать параметры обобщенных типов через атрибут generic:
<script setup lang="ts" generic="T"> defineProps<{ items: T[] selected: T }>() </script>
Значение generic работает точно так же, как список параметров между <…> в TypeScript. Например, можно использовать множественные параметры, ограничения extends, типы по умолчанию и ссылочные импортированные типы:
<script setup lang="ts" generic="T extends string | number, U extends Item"> import type { Item } from './types' defineProps<{ id: T list: U[] }>() </script>
Ранее эта функция требовала явного согласия пользователя, но теперь она включена по умолчанию в последней версии volar / vue-tsc.
-
Обсуждение: RFC#436
-
Относится к generic defineComponent() — PR#7963
Более эргономичный defineEmits
Ранее параметр типа для defineEmits поддерживал только синтаксис сигнатуры вызова:
// Раньше const emit = defineEmits<{ (e: 'foo', id: number): void (e: 'bar', name: string, ...rest: any[]): void }>()
Тип совпадает с типом возврата для emit, но он немного многословен и неудобен в написании. В версии 3.3 представлен более эргономичный способ объявления эмитов с помощью типов:
// Теперь const emit = defineEmits<{ foo: [id: number] bar: [name: string, ...rest: any[]] }>()
В литерале типа ключом является имя события, а значением — тип массива, определяющий дополнительные аргументы. Хотя это не обязательно, вы можете использовать помеченные элементы кортежа для ясности, как в примере выше.
Синтаксис сигнатуры вызова по-прежнему поддерживается.
Типизированные слоты с defineSlots
Новый макрос defineSlots можно использовать для объявления ожидаемых слотов и соответствующих им параметров:
<script setup lang="ts"> defineSlots<{ default?: (props: { msg: string }) => any item?: (props: { id: number }) => any }>() </script>
defineSlots() принимает только параметр типа и никаких рантайм аргументов. Параметр типа должен быть литералом типа, где ключ свойства — имя слота, а значение — функция слота. Первым аргументом функции является проп, который слот ожидает получить, и его тип будет использоваться для пропсов слота в шаблоне. Возвращаемое значение defineSlots — это тот же объект слота, который возвращается из useSlots.
Некоторые текущие ограничения:
-
Проверка требуемых слотов пока не реализована в volar / vue-tsc.
-
Тип возврата функции слота в настоящее время игнорируется и может быть
any, но мы можем использовать его для проверки содержимого слота в будущем.
Существует также соответствующая опция слотов для использования defineComponent. Оба API не имеют последствий во время выполнения и служат исключительно в качестве подсказок типов для IDE и vue-tsc.
Подробнее: PR#7982
Экспериментальные возможности
Реактивные пропсы Деструктура
Ранее являвшаяся частью исчезнувшего Reactivity Transform, деструктура реактивных пропсов была выделена в отдельную функцию.
Эта функция позволяет деструктурированным пропсам сохранять реактивность и обеспечивает более эргономичный способ объявления значений пропсов по умолчанию:
<script setup> import { watchEffect } from 'vue' const { msg = 'hello' } = defineProps(['msg']) watchEffect(() => { // accessing `msg` in watchers and computed getters // tracks it as a dependency, just like accessing `props.msg` console.log(`msg is: ${msg}`) }) </script> <template>{{ msg }}</template>
Эта функция является экспериментальной и требует явного согласия.
Подробнее: RFC#502
defineModel
Ранее, чтобы компонент поддерживал двустороннее связывание с v-model, он должен был (1) объявить пропс и (2) вызвать соответствующее событие update:propName, когда он намеревался обновить пропс:
<!-- ДО --> <script setup> const props = defineProps(['modelValue']) const emit = defineEmits(['update:modelValue']) console.log(props.modelValue) function onInput(e) { emit('update:modelValue', e.target.value) } </script> <template> <input :value="modelValue" @input="onInput" /> </template>
3.3 упрощает использование с помощью нового макроса defineModel. Макрос автоматически регистрирует проп и возвращает ref, который может быть непосредственно изменен:
<!-- ПОСЛЕ --> <script setup> const modelValue = defineModel() console.log(modelValue.value) </script> <template> <input v-model="modelValue" /> </template>
Эта функция является экспериментальной и требует явного согласия.
Подробнее: RFC#503
Другие примечательные возможности
defineOptions
Новый макрос defineOptions позволяет объявлять опции компонента непосредственно в <script setup>, не требуя отдельного блока <script>:
<script setup> defineOptions({ inheritAttrs: false }) </script>
Улучшенная поддержка геттеров с помощью toRef и toValue
toRef был улучшен для поддержки нормализации значений / геттеров / существующих refs внутри refs:
// Равносильно ref(1) toRef(1) // создает readonly ref, который вызывает getter при доступе к .value toRef(() => props.foo) // Возвращает существующий refs как есть toRef(existingRef)
Вызов toRef с геттером аналогичен computed, но может быть более эффективным, если геттер просто выполняет доступ к свойству без дорогостоящих вычислений.
Новый метод toValue обеспечивает обратное, нормализуя значения/геттеры/рефы в значения:
toValue(1) // --> 1 toValue(ref(1)) // --> 1 toValue(() => 1) // --> 1
toValue можно использовать в составных элементах вместо unref, чтобы ваш составной элемент мог принимать геттеры в качестве реактивных источников данных:
// до: выделение ненужных промежуточных ссылок useFeature(computed(() => props.foo)) useFeature(toRef(props, 'foo')) // после: более эффективно и лаконично useFeature(() => props.foo)
Отношения между toRef и toValue аналогичны отношениям между ref и unref, основное отличие заключается в особой обработке функций getter.
Подробнее: PR#7997
Поддержка импорта исходного кода JSX
В настоящее время типы Vue автоматически регистрируют глобальную JSX-типизацию. Это может привести к конфликту при использовании вместе с другими библиотеками, которым необходим вывод типов JSX, в частности React.
Начиная с версии 3.3, Vue поддерживает указание пространства имен JSX через опцию jsxImportSource в TypeScript. Это позволяет пользователям выбирать глобальный или индивидуальный выбор файла в зависимости от их сценария использования.
Для обратной совместимости в версии 3.3 пространство имен JSX по-прежнему регистрируется глобально. Мы планируем убрать глобальную регистрацию по умолчанию в версии 3.4. Если вы используете TSX с Vue, вам следует добавить явный jsxImportSource в tsconfig.json после обновления до 3.3, чтобы избежать поломки в 3.4.
Улучшение инфраструктуры поддержки
Этот релиз основан на многочисленных улучшениях инфраструктуры поддержки, которые позволяют нам двигаться быстрее и увереннее:
-
Сборка в 10 раз быстрее благодаря отделению проверки типов от сборки rollup и переходу от
rollup-plugin-typescript2кrollup-plugin-esbuild. -
Более быстрые тесты благодаря переходу от Jest к Vitest.
-
Более быстрая генерация типов за счет перехода от
@microsoft/api-extractorкrollup-plugin-dts. -
Комплексные регрессионные тесты с помощью ecosystem-ci — отлавливают регрессии в основных зависимых компонентах экосистемы до выпуска релизов!
Как и планировалось, в 2023 году мы намерены начать выпускать более мелкие и частые релизы функций. Следите за новостями!
ссылка на оригинал статьи https://habr.com/ru/articles/735086/
Добавить комментарий