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.
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
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.
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:
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.