Realmente digitando vue

Logomarca


inb4: Este não é outro "configurar" um novo projeto com o tutorial Vue e TypeScript. Vamos mergulhar fundo em tópicos mais complexos!


typescript é incrível. Vue é incrível. Sem dúvida, muitas pessoas tentam agrupá-las . Mas, devido a diferentes motivos, é difícil realmente digitar seu aplicativo Vue . Vamos descobrir quais são os problemas e o que pode ser feito para resolvê-los (ou pelo menos minimizar o impacto).


TLDR


Temos este modelo maravilhoso com Nuxt , Vue , Vuex e jest totalmente digitados. Basta instalá-lo e tudo será coberto por você. Acesse os documentos para saber mais.


E como eu disse, não vou orientá-lo na configuração básica por três razões:


  1. Existem muitos tutoriais existentes sobre isso
  2. Existem muitas ferramentas para começar com um único clique, como o Nuxt e o vue-cli com o plug-in de Nuxt
  3. Já temos o wemake-vue-template onde todas as configurações sobre as quais eu vou falar já estão cobertas

Tipologias de componentes


A primeira expectativa frustrada quando você começa a trabalhar com o Vue e o typescript e depois de digitar os componentes da classe é que as tags <template> e <style> ainda não foram digitadas. Deixe-me mostrar um exemplo:


 <template> <h1 :class="$style.headr"> Hello, {{ usr }}! </h1> </template> <script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' import { Prop } from 'vue-property-decorator' @Component({}) export default class HelloComponent extends Vue { @Prop() user!: string } </script> <style module> .header { /* ... */ } </style> 

Fiz dois erros de digitação aqui: {{ usr }} vez de {{ user }} e $style.headr vez de $style.header . O texto typescript me salvará desses erros? Não, não vai.


O que pode ser feito para corrigi-lo? Bem, existem vários hacks.


Digitando o modelo


Pode-se usar o Vetur com a opção vetur.experimental.templateInterpolationService para verificar seus modelos. Sim, essa é apenas uma verificação baseada no editor e ainda não pode ser usada dentro do IC. Mas, a equipe da Vetur está trabalhando duro para fornecer uma CLI para permitir isso. Acompanhe a edição original , caso esteja interessado.


vetur


A segunda opção é dois testes de gravação de captura instantânea com jest . Ele detectará muitos erros baseados em modelo. E é muito barato em manutenção.


Portanto, a combinação dessas duas ferramentas fornece uma boa experiência para o desenvolvedor com feedback rápido e uma maneira confiável de detectar erros dentro do IC.


Estilos de digitação


Digitar css-module s também é coberto por várias ferramentas externas:



A idéia principal dessas ferramentas é buscar o css-module e criar arquivos de declaração .d.ts partir deles. Seus estilos serão totalmente digitados. Ainda não foi implementado para o Nuxt ou o Vue , mas você pode Nuxt esse problema para avançar.


No entanto, eu pessoalmente não uso nenhuma dessas ferramentas em meus projetos. Eles podem ser úteis para projetos com grandes bases de código e muitos estilos, mas estou bem apenas com instantâneos.


Guias com testes de regressão visual também ajudam muito. @storybook/addon-storyshots é um bom exemplo dessa técnica.


Vuex


A próxima grande Vuex é Vuex . Possui alguma complexidade projetada por projeto para digitar:


 const result: Promise<number> = this.$store.dispatch('action_name', { payload: 1 }) 

O problema é que 'action_name' pode não existir, aceitar outros argumentos ou retornar um tipo diferente. Isso não é o que você espera de um aplicativo totalmente digitado.


Quais são as soluções existentes?


classe vuex


vuex-class é um conjunto de decoradores para permitir acesso fácil dos componentes baseados em classe aos componentes internos do Vuex .


Porém, não é digitado com segurança, pois não pode interferir nos tipos de estado, getters, mutações e ações.


classe vuex


Obviamente, você pode anotar manualmente tipos de propriedades.


anotado na classe vuex


Mas o que você fará quando o tipo real de seu estado, getters, mutações ou ações mudar? Você terá uma incompatibilidade de tipo oculto.


vuex-simple


É aí que o vuex-simple nos ajuda. Na verdade, ele oferece uma maneira completamente diferente de escrever seu código Vuex e é isso que o torna seguro. Vamos dar uma olhada:


 import { Action, Mutation, State, Getter } from 'vuex-simple' class MyStore { // State @State() public comments: CommentType[] = [] // Getters @Getter() public get hasComments (): boolean { return Boolean(this.comments && this.comments.length > 0) } // Mutations @Mutation() public setComments (payload: CommentType[]): void { this.comments = updatedComments } // Actions @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() this.setComments(commentsList) // typed mutation return commentsList } } 

Posteriormente, este módulo digitado pode ser registrado dentro do seu Vuex forma:


 import Vue from 'vue' import Vuex from 'vuex' import { createVuexStore } from 'vuex-simple' import { MyStore } from './store' Vue.use(Vuex) // Creates our typed module instance: const instance = new MyStore() // Returns valid Vuex.Store instance: export default createVuexStore(instance) 

Agora, temos uma instância 100% nativa do Vuex.Store e todas as informações de tipo incluídas. Para usar esse armazenamento digitado no componente, podemos escrever apenas uma linha de código:


 import Vue from 'vue' import Component from 'nuxt-class-component' import { useStore } from 'vuex-simple' import MyStore from './store' @Component({}) export default class MyComponent extends Vue { // That's all we need! typedStore: MyStore = useStore(this.$store) // Demo: will be typed as `Comment[]`: comments = typedStore.comments } 

Agora, Vuex o Vuex que pode ser usado com segurança dentro do nosso projeto.
Quando alteramos algo dentro de nossa definição de loja, ele é automaticamente refletido nos componentes que usam essa loja. Se algo falhar - nós sabemos o mais rápido possível.


Também existem bibliotecas diferentes que fazem o mesmo, mas possuem API diferente. Escolha o que melhor lhe convier.


Chamadas de API


Quando o Vuex configurado corretamente, precisamos preenchê-lo com dados.
Vamos dar uma olhada em nossa definição de ação novamente:


 @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() // ... return commentsList } 

Como podemos saber que ele realmente retornará uma lista de CommentType e não um único number ou AuthorType instâncias de AuthorType ?


Não podemos controlar o servidor. E o servidor pode realmente quebrar o contrato. Ou podemos simplesmente passar a instância da api errada, digitar o erro na URL ou o que for.


Como podemos estar seguros? Podemos usar a digitação em tempo de execução! Deixe-me apresentar io-ts para você:


 import * as ts from 'io-ts' export const Comment = ts.type({ 'id': ts.number, 'body': ts.string, 'email': ts.string, }) // Static TypeScript type, that can be used as a regular `type`: export type CommentType = ts.TypeOf<typeof Comment> 

O que fazemos aqui?


  1. Definimos uma instância de ts.type com campos que precisam ser verificados em tempo de execução quando recebermos uma resposta do servidor
  2. Definimos um tipo estático para ser usado na anotação sem nenhum padrão adicional

E depois podemos usá-lo em nossas chamadas de api :


 import * as ts from 'io-ts' import * as tPromise from 'io-ts-promise' public async fetchComments (): Promise<CommentType[]> { const response = await axios.get('comments') return tPromise.decode(ts.array(Comment), response.data) } 

Com a ajuda do io-ts-promise , podemos retornar uma Promise em um estado com falha se a resposta do servidor não corresponder ao tipo ts.array(Comment) . Realmente funciona como uma validação.


 fetchComments() .then((data) => /* ... */ .catch(/* Happens with both request failure and incorrect response type */) 

Além disso, a anotação do tipo de retorno está sincronizada com o método .decode . E você não pode colocar bobagens aleatórias lá:


io-ts


Com a combinação de verificações em tempo de execução e estáticas, podemos ter certeza de que nossas solicitações não falharão devido à incompatibilidade de tipos.
Mas, para ter 100% de certeza de que tudo funciona, eu recomendaria o uso de testes baseados em contrato: dê uma olhada no pact como exemplo. E monitore seu aplicativo com o Sentry .


Roteador Vue


O próximo problema é que this.$router.push({ name: 'wrong!' }) Não funciona da maneira que queremos.


Eu diria que seria ideal ser avisado pelo compilador de que estamos encaminhando para a direção errada e essa rota não existe.
Mas isso não é possível. E não se pode fazer muito: existem muitas rotas dinâmicas, regex, fallbacks, permissões, etc. que podem eventualmente quebrar. A única opção é testar cada uma this.$router chamadas this.$router no seu aplicativo.


vue-test-utils


Falando sobre testes, não tenho desculpas para não mencionar @vue/test-utils que também tem alguns problemas com a digitação.


Quando tentarmos testar nosso novo componente brilhante com a propriedade typedStore , descobriremos que realmente não podemos fazer isso de acordo com o typescript :


vue-test-utils


Por que isso acontece? Isso acontece porque a chamada mount() não sabe nada sobre o tipo do seu componente, porque todos os componentes têm um tipo VueConstructor<Vue> por padrão:


vue-constructor


É daí que todos os problemas vêm. O que pode ser feito?
Você pode usar o vuetype para produzir tipagens YouComponent.vue.d.ts que informarão seus testes sobre o tipo exato do componente montado.


Você também pode acompanhar esse problema para o progresso.


Mas não gosto dessa ideia. Estes são testes, eles podem falhar. Não é grande coisa.
É por isso que me (wrapper.vm as any).whatever a (wrapper.vm as any).whatever . Isso me poupa bastante tempo para escrever testes. Mas estraga um pouco a Experiência do desenvolvedor.


Tome sua própria decisão aqui:


  • Use o vuetype até o fim
  • Aplique-o parcialmente aos componentes mais importantes com a maior quantidade de testes e atualize-o regularmente
  • Use any como substituto

Conclusão


O nível médio de suporte à typescript no ecossistema Vue aumentou nos últimos dois anos:


  • Nuxt introduziu o nuxt-ts Nuxt primeira vez e agora envia o ts builds por padrão
  • Vue@3 terá suporte aprimorado à typescript
  • Mais aplicativos e plugins de terceiros fornecerão definições de tipo

Mas, é a produção pronta no momento. Estas são apenas algumas coisas para melhorar! Escrever código Vue segurança de tipo realmente melhora sua Experiência do desenvolvedor e permite que você se concentre nas coisas importantes, deixando o trabalho pesado para o compilador.


Quais são os seus hacks e ferramentas favoritos para digitar aplicativos Vue ? Vamos discutir isso na seção de comentários.

Source: https://habr.com/ru/post/pt458632/


All Articles