Menu
Foto por: Artem Sapegin

Vue supervitaminado con TypeScript

Author image

Escrito por

Juan Manuel Castillo

JavaScript siempre ha adolecido de ser un lenguaje débilmente tipado. Esto nos facilita la vida cuando comenzamos a utilizarlo reduciendo la curva de aprendizaje, pero cuando adquirimos experiencia y escribimos código para ser mantenible y robusto, el tipado débil se vuelve en nuestra contra.

Esto ha sido así hasta que llegó TypeScript en 2012 para hacer de él un lenguaje fuertemente tipado, pero... ¿Qué ventajas tenemos al usarlo?.

Principalmente nos ayuda a evitar los molestos errores en tiempo de ejecución pero también nos ayuda en el autocompletado de código y nos obliga a definir mejor los contratos entre las diferentes partes de nuestro código.

El tipado fuerte favorece un código más robusto y cohesionado ya que especificaremos con más profundidad los diferentes contratos entre partes del código, ya no sólo decimos los parámetros que acepta un método sino también de qué tipo son los datos (clases, cadenas, booleanos...).

También supone dedicar más tiempo en el diseño y creación de nuestro código, algo que debes tener en cuenta cuando empieces con TypeScript aunque los beneficios obtenidos merecerán la pena, especialmente en proyectos con muchas líneas de código o que más adelante ganarán en complejidad y tamaño.

Creando el proyecto base

Antes de comenzar, asegúrate de tener instalado Vue CLI. Si no lo tienes, puedes instalarlo con el siguiente comando (Te recomiendo instalar la versión 3).

npm install --global @vue/cli

Si tienes la versión de 3 del CLI y quieres usar los templates (legacy), necesitas instalar el bridge para vue-init.

Creamos el proyecto con el template webpack

vue init webpack ts-example-project

Otra buena alternativa es comenzar desde 0 creando el proyecto paso a paso. Puedes hacerlo usando el siguiente comando y siguiendo los pasos del creador de proyectos en Vue.

vue create ts-example-project

Si no eres muy ducho con la línea de comandos puedes iniciar el entorno gráfico de Vue para crear/modificar proyectos.

vue ui

¿Cómo funciona?

Cuando escribimos código con TypeScript, éste es compilado a JavaScript Vanilla de forma universal, además, es Open Source.

En esta ocasión no entraremos en la sintaxis y potencial de TypeScript pero lo importante que debes entender es que al final obtienes un código en JavaScript perfectamente válido y compatible.

Instalación

Para instalarlo ejecutamos el siguiente comando.

npm install typescript --save-dev

Y pasamos a modificar la configuración del proyecto generado anteriormente.

Primero es necesario crear la configuración para TypeScript en el raíz del proyecto en un fichero que se debe llamar tsconfig.json

{
  "compilerOptions": {
    "lib": ["dom", "es5", "es2015"],
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "allowSyntheticDefaultImports": true
  }
}

En el JSON anterior puedes ver algunas de las opciones, si quieres profundizar puedes ver todas las opciones del compilador.

A continuación instalamos el loader de TypeScript para Webpack. Aunque ya instalamos TypeScript es necesario el loader para que funcione.

Cuidado, si tienes una versión de Webpack anterior a la 4 debes fijar la versión a instalar de ts-loader a la 3.5.0 o de lo contrario tendrás problemas de incompatibilidad.

npm install ts-loader --save-dev
//alternativa cerrando la versión
npm install ts-loader@3.5.0 --save-dev

Añadimos a Webpack la configuración del loader. Para ello edita el fichero de configuración de Webpack añadiendo una nueva regla

rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules|vue\/src/,
        loader: "ts-loader",
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      },

Modificamos el punto de entrada de main.js a main.ts (no olvides renombrar el fichero a main.ts) y añadimos la extensión de TypeScript al listado “.ts”.

...
//nuevo punto de entrada
entry: {
  app: './src/main.ts'
},
...
...
//nueva extensión .ts
resolve: {
    extensions: ['.vue', '.json', '.js', '.ts'],
...

Y por último habilitamos es-module en vue-loader.conf.js

...
module.exports = {
  loaders: ...
  esModule: true,
...

Ahora ya estamos en disposición de ejecutar nuestro proyecto.

npm run dev

Si todo ha ido bien, el servidor habrá arrancado aunque seguramente tendrás errores de compilación. ¿Qué está pasando?, necesitamos adaptar el código a la sintaxis de TypeScript.

En mi caso, prefiero desarrollar los componentes basados en clases por lo que instalamos vue-class-component (paquete oficialmente soportado por Vue) y vue-property-decorator de forma opcional pero muy recomendable. Nos permite usar decoradores para propiedades, modelos, watchers, refs, etc.

//instalación en un único comando
npm install vue-class-component vue-property-decorator --save-dev

vue-property-decorator tiene como dependencia vue-class-component.

Añadimos las siguientes opciones al fichero tsconfig.json para evitar errores y warnings durante la compilación.

"experimentalDecorators": true,
"allowJs": true

Con este último paso ya estamos preparados para crear componentes basados en clases por lo que vamos a modificar primero App.vue (nuestro template principal) y luego HelloWorld.vue (template de la página por defecto).

Antes de continuar un último detalle. En las etiquetas <script> de tus componentes, especifica el lenguaje se está usando

<script lang="ts">
...
</script>

Como hemos optado por usar vue-property-decorator, importaremos éste en lugar de vue-component-class . El código de App.vue quedaría como sigue.

<script lang="ts">
    import {Vue} from 'vue-property-decorator'

    export default class App extends Vue {
		    
    }
</script>

Este componente es el principal y de momento no tiene lógica alguna. Por ahora simplemente importamos vue-property-decorator y luego exportamos la clase App.

Pasamos a modificar el componente HelloWorld pero vamos a darle un poco más de salsa para salirnos de un HelloWorld típico.

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li>
...

En el código del proyecto generado básicamente lo que se hace es imprimir el contenido de la variable msg en pantalla como título (entre otro contenido estático) pero hagamos los siguientes cambios:

  1. El texto seguirá almacenado en la misma variable msg pero se imprimirá en el template a través de un computed
  2. Añadiremos un evento evento click sobre el h1 que mostrará un alert con el mensaje.
  3. Añadiremos una variable clicks que se incrementará con cada click sobre el h1 anterior
  4. Añadiremos un watcher (usando vue-property-decorator) sobre los clicks que enviará a consola el valor anterior y nuevo.

Modificamos el h1 en el template.

...    
<h1 @click.prevent="sayHello">{{ wellcomeMsg }}</h1>
...

Y el código del componente.

<script lang="ts">
    import { Component, Prop, Vue, Watch } from 'vue-property-decorator'

    @Component
    export default class HelloWorld extends Vue {
        // Los datos iniciales pueden ser declarados como propiedades de la instancia
        msg:string = 'Hola Mundo'
        clicks:number = 0

        // Los computados se crearían como getters de la instancia
        get wellcomeMsg():string{
            return this.msg
        }

        // Los métodos pueden ser declarados como métodos de la instancia
        sayHello (): void {
            this.clicks++
            window.alert(this.msg)
        }

        @Watch('clicks')
        onClicksChanged(val: string, oldVal: string) {
            console.info(`clicks en el título: ${val}, anteriormente ${oldVal} clicks`)
        }

    }

</script>

Viendo el código, no hay nada nuevo que no se use ya en ES6 salvo que los tipos devueltos y propiedades, métodos... están tipados. Puede parecer poca cosa pero sólo con esto mejoramos la calidad de nuestro código y evitamos muchos sustos en producción, máxime cuando no hay un set de test de por medio pero esto no ocurre en la realidad ¿cierto? ;)

Ya está listo nuestro mini ejemplo HelloWorld. Sobre este podemos podemos ir probando, añadiendo componentes y en definitiva, trabajar con Vue a otro nivel.

C'est finit. Si te ha gustado y usas Nuxt (o quieres usarlo) para algún proyecto no olvides pasar nuevamente en breve. Tenemos en el horno un artículo sobre Nuxt + TypeScript.

Referencias

Página oficial Vue (soporte TypeScript)

Página oficial TypeScript

GitHub vue-class-component

GitHub vue-property-decorator