Declaração de tipo TS do componente Vue3

Para dizer que a tecnologia de front-end mais quente deste ano, Vue3 e TS estão definitivamente na lista. Entende-se que muitas empresas já estão utilizando Vue3 + TS + Vite para desenvolver novos projetos. Então não podemos ficar para trás. Hoje vou compartilhar com você como usar o tipo TS em combinação com Composition-Api em componentes Vue3. Se tem amigos que não conhecem ou não conhecem, vamos aprender juntos!

Tipos de anotação para adereços

usar configuração

ao usar

<script setup lang="ts">
const props = defineProps({
    
    
  foo: {
    
     type: String, required: true },
  bar: Number
})

props.foo // string
props.bar // number | undefined
</script>

Isso é chamado de declaração de tempo de execução porque os argumentos passados ​​para defineProps() são usados ​​como opções props em tempo de execução.

A segunda forma é definir o tipo de props através de parâmetros genéricos, que é mais direto:

<script setup lang="ts">
const props = defineProps<{
    
    
  foo: string
  bar?: number
}>()
</script>

Isso é conhecido como declaração baseada em tipo, e o compilador tenta deduzir opções de tempo de execução equivalentes com base nos parâmetros de tipo tanto quanto possível.

Também poderíamos mover o tipo de props para uma interface separada:

<script setup lang="ts">
interface Props {
    
    
  foo: string
  bar?: number
}

const props = defineProps<Props>()
</script>

A abordagem baseada em tipo é mais concisa, mas perde a capacidade de definir valores padrão para props. Podemos resolver isso com o açúcar sintático responsivo atualmente experimental:

<script setup lang="ts">
interface Props {
    
    
  foo: string
  bar?: number
}

// Padrões de açúcar sintático responsivo serão compilados em opções de tempo de execução equivalentes
const { foo, bar = 100 } = defineProps()

Este comportamento atualmente precisa ser explicitamente aceito na configuração:

// vite.config.js
export default {
    
    
  plugins: [
    vue({
    
    
      reactivityTransform: true
    })
  ]
}

// vue.config.js
module.exports = {
    
    
  chainWebpack: (config) => {
    
    
    config.module
      .rule('vue')
      .use('vue-loader')
      .tap((options) => {
    
    
        return {
    
    
          ...options,
          reactivityTransform: true
        }
      })
  }
}

configurar

se não for usado

import {
    
     defineComponent } from 'vue'

export default defineComponent({
    
    
  props: {
    
    
    message: String
  },
  setup(props) {
    
    
    props.message // <-- 类型:string
  }
})

Tipo de anotação para emissões

configurar

existir

<script setup lang="ts">
// 运行时
const emit = defineEmits(['change', 'update'])

// 基于类型
const emit = defineEmits<{
    
    
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>

Podemos ver que as declarações baseadas em tipo nos fornecem um controle mais refinado sobre os tipos de eventos que são acionados.

não configurado

se não for usado

import {
    
     defineComponent } from 'vue'

export default defineComponent({
    
    
  emits: ['change'],
  setup(props, {
     
      emit }) {
    
    
    emit('change') // <-- 类型检查 / 自动补全
  }
})

Anote o tipo para ref()

tipo de derivação padrão

Uma ref deduz automaticamente seu tipo do valor com o qual foi inicializada:

import {
    
     ref } from 'vue'

// 推导出的类型:Ref<number>
const year = ref(2020)

// => TS Error: Type 'string' is not assignable to type 'number'.
year.value = '2020'

especificando um tipo por meio de uma interface

Às vezes podemos querer especificar um tipo mais complexo para o valor em ref, usando a interface Ref:

import {
    
     ref } from 'vue'
import type {
    
     Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020 // 成功!

Especificando tipos por meio de genéricos

Como alternativa, passe um argumento genérico para ref() para substituir o comportamento de dedução padrão:

// 得到的类型:Ref<string | number>
const year = ref<string | number>('2020')

year.value = 2020 // 成功!

Se você especificar um parâmetro genérico sem um valor inicial, acabará com um tipo de união contendo indefinido:

// 推导得到的类型:Ref<number | undefined>
const n = ref<number>()

Tipo de anotação para reativo ()

tipo de derivação padrão

reactivo() também deduz implicitamente os tipos de seus argumentos:

import {
    
     reactive } from 'vue'

// 推导得到的类型:{ title: string }
const book = reactive({
    
     title: 'Vue 3 指引' })

especificando um tipo por meio de uma interface

Para especificar explicitamente o tipo de uma variável reativa, podemos usar interfaces:

import {
    
     reactive } from 'vue'

interface Book {
    
    
  title: string
  year?: number
}

const book: Book = reactive({
    
     title: 'Vue 3 指引' })

Anote o tipo para computer()

tipo de derivação padrão

computered() deduz automaticamente o tipo do valor de retorno de sua função computada:

import {
    
     ref, computed } from 'vue'

const count = ref(0)

// 推导得到的类型:ComputedRef<number>
const double = computed(() => count.value * 2)

// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')

Especificando tipos por meio de genéricos

Você também pode especificar explicitamente o tipo por meio de um parâmetro genérico:

const double = computed<number>(() => {
    
    
  // 若返回值不是 number 类型则会报错
})

Anotar tipos para manipuladores de eventos

Ao lidar com eventos DOM nativos, os parâmetros do manipulador de eventos devem ser marcados corretamente com tipos. Vejamos este exemplo:

<script setup lang="ts">
function handleChange(event) {
    
    
  // `event` 隐式地标注为 `any` 类型
  console.log(event.target.value)
}
</script>

<template>
  <input type="text" @change="handleChange" />
</template>

Quando não houver anotação de tipo, o parâmetro de evento será marcado implicitamente como qualquer tipo. Isso também gerará um erro TS se "strict": true ou "noImplicitAny": true estiver configurado em tsconfig.json. Portanto, é recomendável digitar explicitamente os parâmetros das funções do manipulador de eventos. Além disso, pode ser necessário converter propriedades explicitamente no evento:

function handleChange(event: Event) {
    
    
  console.log((event.target as HTMLInputElement).value)
}

Tipo de anotação para fornecer / injetar

provide e inject geralmente rodam em componentes diferentes. Para marcar corretamente o tipo do valor injetado, o Vue fornece uma interface InjectionKey, que é um tipo genérico herdado do Symbol, que pode ser usado para sincronizar o tipo de valor injetado entre o provedor e o consumidor:

import {
    
     provide, inject } from 'vue'
import type {
    
     InjectionKey } from 'vue'

const key = Symbol() as InjectionKey<string>

provide(key, 'foo') // 若提供的是非字符串值会导致错误

const foo = inject(key) // foo 的类型:string | undefined

Recomenda-se colocar o tipo de chave injetada em um arquivo separado para que possa ser importado por vários componentes.

Ao usar uma string para injetar a chave, o tipo do valor injetado é desconhecido, o que precisa ser declarado explicitamente através do parâmetro genérico:

const foo = inject<string>('key') // 类型:string | undefined

Observe que o valor injetado ainda pode ser indefinido, pois não há garantia de que o provedor fornecerá esse valor em tempo de execução. Quando um valor padrão é fornecido, o tipo indefinido pode ser removido:

const foo = inject<string>('foo', 'bar') // 类型:string

Você também pode converter o valor se tiver certeza de que o valor sempre será fornecido:

const foo = inject('foo') as string

#Tipo de anotação para referência de modelo dom
O modelo ref precisa ser criado com um parâmetro genérico explicitamente especificado e um valor inicial nulo:

<script setup lang="ts">
import {
    
     ref, onMounted } from 'vue'

const el = ref<HTMLInputElement | null>(null)

onMounted(() => {
    
    
  el.value?.focus()
})
</script>

<template>
  <input ref="el" />
</template>

Observe que, para segurança de tipo estrita, é necessário usar encadeamento opcional ou guardas de tipo ao acessar el.value. Isso ocorre porque até que o componente seja montado, o valor dessa referência é inicialmente nulo e v-if também será definido como nulo quando o elemento referenciado for desmontado.

#Consulte o tipo de anotação para o modelo de componente
Às vezes, precisamos adicionar uma referência de modelo a um subcomponente para chamar os métodos que ele expõe. Por exemplo, temos um subcomponente MyModal que possui um método para abrir um modal:

<!-- MyModal.vue -->
<script setup lang="ts">
import {
    
     ref } from 'vue'

const isContentShown = ref(false)
const open = () => (isContentShown.value = true)

defineExpose({
    
    
  open
})
</script>

Para obter o tipo de MyModal, primeiro precisamos obter seu tipo por meio de typeof e, em seguida, usar o tipo de ferramenta InstanceType integrado do TypeScript para obter seu tipo de instância:

<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'

const modal = ref<InstanceType<typeof MyModal> | null>(null)

const openModal = () => {
    
    
  modal.value?.open()
}
</script>

Acho que você gosta

Origin blog.csdn.net/weixin_44064067/article/details/127067031
Recomendado
Clasificación