Vue 3 typescript directive

# Поддержка TypeScript

Vue CLI (opens new window) предоставляет встроенную поддержку TypeScript из коробки.

# Официальные декларации типов в npm-пакетах

Статическая система типов может помочь предотвратить многие потенциальные ошибки по мере роста приложения, поэтому Vue 3 написан на TypeScript. А значит, для использования TypeScript во Vue не нужны никакие дополнительные инструменты — он уже поставляется с отличной поддержкой.

# Рекомендуемая конфигурация

// tsconfig.json  "compilerOptions":  "target": "esnext", "module": "esnext", // использование более строгого вывода типов для свойств данных в `this` "strict": true, "jsx": "preserve", "moduleResolution": "node" > > 

Обратите внимание, требуется включать strict: true (или хотя бы noImplicitThis: true , который является частью флага strict ), чтобы проверять this в методах компонента, иначе он всегда будет интерпретироваться как тип any .

# Конфигурация Webpack

При использовании пользовательской конфигурации Webpack ts-loader необходимо настроить для парсинга блоков во .vue файлах:

// webpack.config.js module.exports =  . module:  rules: [  test: /\.tsx?$/, loader: 'ts-loader', options:  appendTsSuffixTo: [/\.vue$/], >, exclude: /node_modules/, >,  test: /\.vue$/, loader: 'vue-loader', > . 

# Инструменты для разработки

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

(opens new window) умеет генерировать новые проекты, которые будут использовать TypeScript:

# 1. Устанавливаем Vue CLI, если ещё не установлен npm install --global @vue/cli # 2. Создаём новый проект, затем выбираем опцию "Manually select features" vue create my-project-name # В существующий проект Vue CLI без TypeScript # можно добавить его поддержку с помощью плагина для Vue CLI: vue add typescript 

Убедитесь, что для секции script компонента в качестве языка указан TypeScript:

Или при желании совмещать использование TypeScript с JSX render -функцией:

# Поддержка в редакторах

Для разработки приложений Vue на TypeScript настоятельно рекомендуем использовать Visual Studio Code

(opens new window) , обеспечивающее отличную поддержку TypeScript из коробки. При использовании однофайловых компонентов (SFC) также установите расширение Volar

(opens new window) , которое добавит вывод типов TypeScript в них и множество других отличных возможностей.

(opens new window) из коробки поддерживают как TypeScript, так и Vue. Другие IDE от JetBrains также имеют поддержку из коробки или через бесплатный плагин

# Объявление компонентов Vue

Чтобы TypeScript правильно определял типы внутри опций компонентов Vue необходимо объявлять компоненты с помощью глобального метода defineComponent :

import  defineComponent > from 'vue' const Component = defineComponent( // вывод типов будет работать >) 

При использовании однофайловых компонентов это будет выглядеть так:

script lang="ts"> import  defineComponent > from 'vue' export default defineComponent( // вывод типов будет работать >) script> 

# Использование с Options API

TypeScript умеет выводить большинство типов без их явного определения. Например, если есть компонент со свойством count , то будет выведена ошибка при попытке вызывать строковый метод на этом свойстве:

const Component = defineComponent( data()  return  count: 0 > >, mounted()  const result = this.count.split('') // => Property 'split' does not exist on type 'number' > >) 

К сложным типам или интерфейсам можно приводить с использованием type assertion

interface Book  title: string author: string year: number > const Component = defineComponent( data()  return  book:  title: 'Руководство по Vue 3', author: 'Команда Vue', year: 2022 > as Book > > >) 

# Расширение типов для globalProperties

Для добавления глобальных свойств, доступных в любом экземпляре компонента, Vue 3 предоставляет объект globalProperties . Например, для плагина может потребоваться внедрить глобальный объект или функцию.

import axios from 'axios' import  createApp > from 'vue' const app = createApp(>) // Пользовательское объявление глобального свойства app.config.globalProperties.$http = axios // Плагин для валидации некоторых данных export default  install(app, options)  app.config.globalProperties.$validate = (data: object, rule: object) =>  // проверка, что объект соответствует определённым правилам > > > 

Сообщить TypeScript об этих новых свойствах можно используя расширение модуля

Для примера выше потребовалось бы добавить следующее объявление типа:

import axios from 'axios' declare module '@vue/runtime-core'  export interface ComponentCustomProperties  $http: typeof axios $validate: (data: object, rule: object) => boolean > > 

Объявление типа можно указать в этом же файле или в общем файле *.d.ts всего проекта (например, в src/typings , чтобы он автоматически загружался TypeScript). Разработчикам библиотек и плагинов нужно указать этот файл в файле package.json в свойстве types .

Убедитесь, что файл декларации является модулем TypeScript

Чтобы воспользоваться преимуществами расширения модуля, нужно убедиться что в файле будет хотя бы один import или export корневого уровня, даже если это будет просто export <> .

Любой файл с import или export корневого уровня рассматривается как модуль в TypeScript

(opens new window) . Если объявление типов сделано вне модуля, то они перезапишут исходные типы, а не расширят их.

Подробнее о типе ComponentCustomProperties смотрите в его определении в @vue/runtime-core

# Аннотация возвращаемых типов

Из-за цикличной природы файлов деклараций Vue, TypeScript может испытывать трудности с выводом типа вычисляемых свойств. По этой причине может потребоваться аннотировать возвращаемый тип вычисляемых свойств.

import  defineComponent > from 'vue' const Component = defineComponent( data()  return  message: 'Привет' > >, computed:  // требуется аннотация типа greeting(): string  return this.message + '!' >, // при использовании сеттера, нужна аннотация для геттера greetingUppercased:  get(): string  return this.greeting.toUpperCase() >, set(newValue: string)  this.message = newValue.toUpperCase() > > > >) 

# Аннотация входных параметров

Входные параметры по указанному type проверяются во время выполнения. Чтобы передать эти типы в TypeScript потребуется приводить конструктор с помощью PropType :

import  defineComponent, PropType > from 'vue' interface Book  title: string author: string year: number > const Component = defineComponent( props:  name: String, id: [Number, String], success:  type: String >, callback:  type: Function as PropType() => void> >, book:  type: Object as PropTypeBook>, required: true >, metadata:  type: null // metadata будет с типом any > > >) 

(opens new window) TypeScript, когда дело доходит до вывода типов выражений функций, необходимо быть осторожным со значениями validator и default для объектов и массивов:

import  defineComponent, PropType > from 'vue' interface Book  title: string year?: number > const Component = defineComponent( props:  bookA:  type: Object as PropTypeBook>, // Убедитесь, что используете стрелочную функцию default: () => ( title: 'Выражение со стрелочной функцией' >), validator: (book: Book) => !!book.title >, bookB:  type: Object as PropTypeBook>, // Или явно указывайте this параметром default(this: void)  return  title: 'Выражение с функцией' > >, validator(this: void, book: Book)  return !!book.title > > > >) 

# Аннотация событий

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

const Component = defineComponent( emits:  addBook(payload:  bookName: string >)  // валидации во время выполнения return payload.bookName.length > 0 > >, methods:  onSubmit()  this.$emit('addBook',  bookName: 123 // Ошибка типа! >) this.$emit('non-declared-event') // Ошибка типа! > > >) 

# Использование с Composition API

В функции setup() не требуется указывать типы для параметра props , так как они будут выводиться из опции props компонента.

import  defineComponent > from 'vue' const Component = defineComponent( props:  message:  type: String, required: true > >, setup(props)  const result = props.message.split('') // ОК, потому что 'message' строка const filtered = props.message.filter(p => p.value) // ОШИБКА: Property 'filter' does not exist on type 'string' > >) 

# Типизация ссылок на элементы шаблона

Иногда может потребоваться аннотировать ссылку в шаблоне на дочерний компонент, чтобы вызвать его публичный метод. Например, есть дочерний компонент MyModal с методом, который открывает модальное окно:

import  defineComponent, ref > from 'vue' const MyModal = defineComponent( setup()  const isContentShown = ref(false) const open = () => (isContentShown.value = true) return  isContentShown, open > > >) 

И вызвать этот метод из родительского компонента через ссылку на элемент шаблона:

import  defineComponent, ref > from 'vue' const MyModal = defineComponent( setup()  const isContentShown = ref(false) const open = () => (isContentShown.value = true) return  isContentShown, open > > >) const app = defineComponent( components:  MyModal >, template: `  `, setup()  const modal = ref() const openModal = () =>  modal.value.open() > return  modal, openModal > > >) 

Хоть это будет работать, но не будет никакой информации о типе MyModal и его доступных методах. Чтобы исправить это, нужно при создании ref-ссылки использовать InstanceType :

setup()  const modal = refInstanceTypetypeof MyModal>>() const openModal = () =>  modal.value?.open() > return  modal, openModal > > 

Обратите внимание, что необходимо воспользоваться оператором optional chaining

(opens new window) или любым другим способом, чтобы проверять, что modal.value не будет undefined.

# Типизация refs

Ref-ссылки выводят тип из исходного значения:

import  defineComponent, ref > from 'vue' const Component = defineComponent( setup()  const year = ref(2022) const result = year.value.split('') // => Property 'split' does not exist on type 'number' > >) 

Иногда может потребоваться указать сложный тип для внутреннего значения ref-ссылки. Это можно сделать передав общий аргумент при вызове ссылки для переопределения вывода типа по умолчанию:

const year = refstring | number>('2022') // тип year: Ref year.value = 2022 // ОК! 

Если generic тип неизвестен, рекомендуется приводить ref к Ref .

# Типизация reactive

При типизации свойства reactive можно использовать интерфейсы:

import  defineComponent, reactive > from 'vue' interface Book  title: string year?: number > export default defineComponent( name: 'HelloWorld', setup()  const book = reactiveBook>( title: 'Руководство по Vue 3' >) // ИЛИ const book: Book = reactive( title: 'Руководство по Vue 3' >) // ИЛИ const book = reactive( title: 'Руководство по Vue 3' >) as Book > >) 

# Типизация computed

Вычисляемые свойства автоматически выводят тип из возвращаемого значения:

import  defineComponent, ref, computed > from 'vue' export default defineComponent( name: 'CounterButton', setup()  let count = ref(0) // только для чтения const doubleCount = computed(() => count.value * 2) const result = doubleCount.value.split('') // => Property 'split' does not exist on type 'number' > >) 

# Типизация обработчиков событий

Работая с нативными событиями DOM может быть полезным типизировать аргумент, передаваемый в обработчик события. Например:

template> input type="text" @change="handleChange" /> template> script lang="ts"> import  defineComponent > from 'vue' export default defineComponent( setup()  // `evt` будет с типом `any` const handleChange = evt =>  console.log(evt.target.value) // TypeScript здесь выбросит ошибку > return  handleChange > > >) script> 

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

const handleChange = (evt: Event) =>  console.log((evt.target as HTMLInputElement).value) > 

(opens new window)
Последнее обновление страницы: около 1 года назад

Источник

Читайте также:  Python which modules are available
Оцените статью