Botón para abrir el Menú Botón para cerrar el Menú
Logo da empresa Alura
Iniciar Sesión Nuestros Planes
Formaciones Conoce a Luri
  • Programación _
  • Front End _
  • Data Science _
  • DevOps _
  • Innovación y Gestión _
Artículos de Tecnología

TypeScript con JavaScript Vanilla

TypeScript con JavaScript Vanilla
Vinicios Neves
Vinicios Neves
26 de Diciembre

Compartir

portada-articulo

¡Bienvenido a esta aventura por el maravilloso mundo del TypeScript! Estoy súper emocionado de que estés aquí conmigo, porque hoy vamos a construir juntos un proyecto y, durante esta jornada, desentrañaremos los conceptos más importantes que TypeScript tiene para ofrecer.

Lo sé, aprender una nueva tecnología puede parecer un poco intimidante al principio, ¡pero no te preocupes! Estoy aquí para guiarte paso a paso, aclarar tus dudas y garantizar que esta experiencia sea divertida y enriquecedora. Y, claro, estamos aquí para aprender juntos, así que ¡cualquier caída es solo una oportunidad de crecimiento!

Vamos a crear una pequeña aplicación de Lista de Compras utilizando TypeScript y, mientras desarrollamos, te mostraré cómo este increíble lenguaje puede ayudarte a maximizar tu productividad y reducir errores inesperados. ¿Adivina qué? ¡Haremos todo esto en un entorno Vanilla! Sí, leíste bien, sin frameworks complejos, solo el bueno y viejo JavaScript, con un ¡toque especial de TypeScript!

Entonces, ¿preparado para embarcar en esta jornada junto a mí? Vamos a aprender, codificar, enfrentar algunos desafíos, y lo más importante, ¡divertirnos en este proceso! Toma tu taza de café (o té, si prefieres), ajusta tu IDE y ¡vamos a comenzar este increíble viaje por TypeScript!

Manos a la obra: configurando y creando una lista de compras

¡Qué sensación increíble empezar algo nuevo, ¿verdad? ¡Siento las mismas mariposas en mi estómago que tú! Así que, relájate, respira hondo y vamos a empezar por configurar nuestro ambiente de desarrollo.

Configurando un proyecto Vanilla con TypeScript

Primero, vamos a aclarar una duda que puede estar pasando por tu cabeza: "¿Qué es Vanilla en este contexto?". Cuando hablamos de Vanilla en desarrollo web, nos referimos a JavaScript puro, sin frameworks o bibliotecas externas. Es lo básico de lo básico, el ingrediente en su forma más simple y pura, por eso el nombre "Vanilla".

Para empezar, necesitas tener Node.js y NPM (Node Package Manager) descargados en tu máquina. Ellos serán nuestros fieles escuderos, ayudando a gestionar paquetes y a ejecutar nuestro proyecto. Si no los tienes descargados, te dejo este artículo que te brindará el paso a paso.

Con Node.js y NPM listos, abre tu terminal y crea un nuevo directorio para nuestro proyecto. Siéntete como en casa, elige un lugar que te guste en tu computadora e inicializa un nuevo proyecto Node.js con el comando npm init -y.

¡Estamos bien! Ahora, el siguiente paso es instalar TypeScript. Lo utilizaremos bastante, así que escribe npm install -g typescript para descargarlo en tu máquina.

¡Ya estás casi listo! Dentro del directorio raíz del proyecto, crea un archivo llamado tsconfig.json. Este archivo es la fuente de verdad para la configuración de cómo queremos que TypeScript se comporte en relación a nuestro proyecto. Nos permite activar y desactivar funcionalidades. Empecemos con algunas pocas configuraciones:

{
    "compilerOptions": {
      "target": "es2015", 
      "module": "commonjs",
      "rootDir": "./",
      "outDir": "./dist",
      "lib": ["es2015", "dom"], // Incluye las bibliotecas necesarias para ES2015 y DOM
    },
    "include": ["./**/*"],  // Incluir todos los archivos en el directorio actual y subdirectorios
    "exclude": ["node_modules", "dist"]  // Excluir "node_modules" y "dist"
  }

¿Vamos a revisar un poco qué hace cada configuración?

  • target: "es2015": Define la versión de ECMAScript que el código compilado seguirá. En este caso, se elige "es2015" para aprovechar las nuevas características de ES6.
  • module: "commonjs": Especifica el sistema de módulos que se usará. "commonjs" es ideal para proyectos Node.js, ya que es ampliamente soportado y estándar en ese entorno.
  • rootDir: "./": Indica el directorio raíz donde se encuentran los archivos TypeScript. Es el punto de partida para la compilación.
  • outDir: "./dist": Especifica el directorio donde TypeScript guardará los archivos JavaScript compilados. Mantiene el código compilado separado del código fuente.
  • lib: ["es2015", "dom"]: Incluye las bibliotecas necesarias para el soporte de ES2015 y del DOM, lo que es útil si el proyecto interactúa con el navegador.
  • include: ["./**/*"]: Incluye todos los archivos dentro del directorio actual y sus subdirectorios en el proceso de compilación.
  • exclude: ["node_modules", "dist"]: Excluye los directorios "node_modules" y "dist" del proceso de compilación, para evitar incluir dependencias externas o archivos compilados anteriores.

Si aún no conoces todos estos conceptos de NPM y paquetes, y quieres profundizar más en la teoría detrás de la práctica, te invito a ver nuestro AluraTips con el instructor Leonardo Castillo.

Repara que, para seguir codificando aquí, no es estrictamente necesario tener toda esta bagaje teórica. ¡Siéntete libre de elegir lo que mejor se adapte a tu momento!

Construyendo la lista de compras

Vamos a comenzar creando nuestro archivo index.html. Este archivo será la puerta de entrada de nuestra aplicación. Para dar un toque especial a la interfaz, vamos a utilizar Bootstrap. Si no estás familiarizado con ello, es un framework de CSS que nos ayuda a estilizar nuestra aplicación de forma más eficiente. Si quieres profundizar más sobre Bootstrap, te sugiero este artículo.

De hecho, probablemente siempre sugeriré contenido adicional para temas que exploraremos en profundidad aquí, ¿vale?

Ahora, agrega el CSS de Bootstrap en nuestro HTML así:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <title>Lista de Compras con TypeScript</title>
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h1>Lista de Compras con TypeScript</h1>
        <form id="formularioItem">
            <div class="form-group">
                <label for="item">Artículo:</label>
                <input type="text" class="form-control" id="item" required>
            </div>
            <button type="submit" class="btn btn-primary">Agregar</button>
        </form>
        <ul id="listaItems" class="list-group mt-3">
            <!-- Los artículos de la lista serán insertados aquí -->
        </ul>
    </div>
    <script src="app.js"></script>
</body>
</html>

Ahora, probablemente te estés preguntando: "¿Por qué no empezamos a escribir el CRUD directamente dentro de una etiqueta <script>?" Bueno, ¡aquí viene una peculiaridad de TypeScript! Vamos a crear un archivo .ts separado porque, a diferencia del JavaScript, TypeScript necesita ser "compilado".

Vamos a crear ahora un archivo llamado app.ts. Finalmente, podemos comenzar a escribir nuestra aplicación. Empecemos con la base de nuestra aplicación. Necesitamos definir cómo es un ítem de la lista de compras, qué propiedades debería tener y cuál es el tipo de cada una de estas propiedades. En TypeScript, una interfaz es una forma poderosa de definir contratos dentro de tu código y con el código fuera de tu proyecto. En nuestro caso, la interfaz Item se define así:

interface Item{
  id: string;
  nombre: string;
}

Esta interfaz está describiendo la forma que un objeto Item debe tener. En este caso, todo ítem debe tener un id y un nombre, ambos del tipo string. Al usar esta interface, estamos básicamente diciendo a TypeScript: "¡Oye, queremos objetos que tengan esta forma específica!". Esto nos proporciona más seguridad, porque TypeScript generará un error si intentamos crear un ítem que no se adhiera a esta forma.

Para interactuar con el DOM, necesitamos seleccionar los elementos con los cuales deseamos trabajar. Sin embargo, TypeScript no conoce el tipo de elemento que document.getElementById retornará, por eso necesitamos usar el type casting para informar a TypeScript del tipo de elemento con el que estamos trabajando:

// Seleccionando elementos del DOM
const formularioItem = document.getElementById('formularioItem') as HTMLFormElement;
const listaItems = document.getElementById('listaItems') as HTMLUListElement;
const inputItem = document.getElementById('item') as HTMLInputElement;

En estos casos, estamos utilizando el type assertion para informar a TypeScript que formularioItem es un elemento de formulario, listaItems es una lista no ordenada y inputItem es un elemento de entrada. Esto es importante porque ahora TypeScript sabe cuáles propiedades y métodos están disponibles para estos elementos, mejorando la autocompletación y detectando errores.

Debes estar preguntándote: ¿de dónde vienen estos tipos que usamos para el type assertion? Bien, ellos son parte de las definiciones de tipos del DOM (Document Object Model) proporcionadas por TypeScript. Cuando trabajas con TypeScript en el ambiente del navegador, el compilador utiliza un conjunto de definiciones de tipos llamado lib.dom.d.ts para comprender los tipos asociados al DOM. Estos tipos representan los elementos HTML y sus propiedades, métodos y eventos, y están derivados de las especificaciones web. Por lo tanto, HTMLFormElement, HTMLUListElement y HTMLInputElement son tipos que representan, respectivamente, un elemento de formulario HTML, una lista no ordenada y un elemento de entrada. Utilizarlos proporciona autocompletado de código inteligente y verificaciones de tipo, facilitando la manipulación segura de los elementos del DOM.

Vamos ahora a crear una función que cargue nuestros ítems:

// Cargando ítems del localStorage
const cargarItems = (): Item[] => {
    const items = localStorage.getItem('items');
    return items ? JSON.parse(items) : [];
};

Creo que, aunque sea una función sencilla de 4 líneas, enseña bastante para nosotros

  • Tipado de retorno Item[]: La función tiene un tipo de retorno explícito Item[], que indica que esta función retornará un array de objetos del tipo Item. Tipar explícitamente la función es una práctica recomendada en TypeScript para garantizar la consistencia de los tipos de datos manipulados en la aplicación. Es decir, quien llame a esta función ya sabe lo que puede esperar de ella.
  • La línea const items = localStorage.getItem('items'): busca en localStorage una entrada con la llave 'items'. Si se encuentra, la entrada es asignada a la constante items como una cadena JSON.
  • Condicional ternario y JSON.parse: La línea return items ? JSON.parse(items) : []; usa un operador ternario. Si items es verdadero (es decir, si la entrada 'items' existe en el localStorage), la función retornará el valor de items parseado de vuelta a un objeto JavaScript utilizando JSON.parse(items). De lo contrario, la función retornará un array vacío [].

Esta aproximación proporciona un manejo seguro y eficiente de datos, garantizando que la aplicación pueda lidiar adecuadamente con escenarios donde 'items' puede no estar presente en el localStorage.

// Guardando elementos en el localStorage
const guardarElementos = (elementos: Item[]) => {
    localStorage.setItem('elementos', JSON.stringify(elementos));
};

En esta función, estamos tratando el concepto de tipado implícito. Esto ocurre porque, aunque estamos especificando el tipo del parámetro de entrada items como un array de Item, no estamos anotando explícitamente el tipo de retorno de la función. TypeScript es lo suficientemente inteligente para inferir el tipo de retorno basado en lo que la función hace. En este caso, como la función no tiene una instrucción de retorno, TypeScript infiera que el tipo de retorno es void, lo que significa que la función no retorna nada. También podemos hacerlo de forma explícita así:

// Guardando elementos en localStorage
const guardarElementos = (elementos: Elemento[]): void => {
    localStorage.setItem('elementos', JSON.stringify(elementos));
};

¿Notaste la diferencia? Agrega : void al final de la declaración de la función. Esta es una forma de decir explícitamente a TypeScript: "¡Oye, esta función no va a retornar nada!"

El tipo void se utiliza para representar la ausencia de un valor. Cuando decimos que una función es del tipo void, estamos afirmando que esta función no retorna ningún valor. En pocas palabras, es como si la función dijera: "¡Voy a realizar una tarea, pero no voy a devolver ningún resultado para ti!"

Ahora que ya tenemos una idea de cómo TypeScript maneja las cosas (ba dum tsss), vamos a escribir el resto de nuestra aplicación. Necesitamos los métodos:

  • agregarItem
  • removerItem
  • editarItem
  • renderizarItens

Además de eso, necesitaremos agregar un listener que escuche el evento de submit del formulario. ¿Qué tal si experimentas? Aún no hemos podido probar, pero puedes comparar el resultado con el mío y aprender de las diferencias. Si quieres, incluso puedes publicar tu versión. ¡Adelante! Y si lo haces, márcame en Instagram o en LinkedIn.

En mi versión completa del app.ts quedó así:

// Definiendo la interfaz para el tipo Item
interface Item {
    id: string;
    nombre: string;
}

// Seleccionando elementos del DOM
const formularioItem = document.getElementById('formularioItem') as HTMLFormElement;
const listaItems = document.getElementById('listaItems') as HTMLUListElement;
const inputItem = document.getElementById('item') as HTMLInputElement;

// Cargando items desde localStorage
const cargarItems = (): Item[] => {
    const items = localStorage.getItem('items');
    return items ? JSON.parse(items) : [];
};

// Guardando items en localStorage
const guardarItems = (items: Item[]) => {
    localStorage.setItem('items', JSON.stringify(items));
};

// Añadiendo un nuevo item
const agregarItem = (nombre: string) => {
    const items = cargarItems();
    const nuevoItem: Item = {
        id: new Date().toISOString(),
        nombre
    };
    items.push(nuevoItem);
    guardarItems(items);
};

// Eliminando un item por ID
const eliminarItem = (id: string) => {
    const items = cargarItems();
    const itemsActualizados = items.filter(item => item.id !== id);
    guardarItems(itemsActualizados);
};

// Editando un item por ID
const editarItem = (id: string, nuevoNombre: string) => {
    const items = cargarItems();
    const item = items.find(item => item.id === id);
    if (item) {
        item.nombre = nuevoNombre;
        guardarItems(items);
    }
};

// Renderizando la lista de items
const renderizarItems = () => {
    const items = cargarItems();
    listaItems.innerHTML = '';
    items.forEach(item => {
        const listItem = document.createElement('li');
        listItem.className = 'list-group-item';
        listItem.textContent = item.nombre;
        listaItems.appendChild(listItem);

        // Añadiendo eventos para editar y eliminar el item
        listItem.addEventListener('dblclick', () => {
            const nuevoNombre = prompt('Editar item:', item.nombre);
            if (nuevoNombre !== null) editarItem(item.id, nuevoNombre);
            renderizarItems();
        });

    });
};

// Inicializando la aplicación
formularioItem.addEventListener('submit', (e) => {
    e.preventDefault();
    const nombre = inputItem.value.trim();
    if (nombre) {
        agregarItem(nombre);
        inputItem.value = '';
        renderizarItems();
    }
});

// Renderizando items al cargar la página
renderizarItems();

¡Perfecto! Ya tenemos nuestro app.ts todo listo, lleno de funcionalidades y con una pizca de aprendizaje sobre TypeScript. Ahora, vamos a entrar en una parte igualmente emocionante: compilar nuestro código TypeScript a JavaScript, incluirlo en nuestro index.html y ¡finalmente ver nuestra aplicación cobrar vida!

Compilando TypeScript a JavaScript

¡Entonces, comencemos! Abre la terminal y, en el directorio del proyecto, ingresa el siguiente comando:

tsc

Este comando instruirá a TypeScript a compilar el archivo app.ts a JavaScript, generando un archivo app.js. ¿Recuerdas nuestro tsconfig.json? Ya está configurado para ayudar en este proceso, así que no necesitamos preocuparnos por detalles adicionales por el momento.

¿Recuerdas que, cuando preparábamos nuestro ambiente, descargamos TypeScript globalmente? Es por eso que ahora podemos ejecutar el comando tsc, porque NPM descargó en nuestra computadora todo lo que TypeScript necesita. Es bueno ver cómo las cosas se conectan, ¿no?

Con el app.js generado, necesitamos incluirlo en nuestro index.html. Para eso, agrega la siguiente etiqueta <script> al final del <body> de tu HTML:

<script src="app.js"></script>

De esta forma, estamos conectando el archivo JavaScript generado a nuestro HTML, y todo el código que escribimos en TypeScript será ejecutado correctamente en nuestro navegador.

Probando la aplicación

¡Ahora es el momento que estábamos esperando! Abre el archivo index.html en tu navegador preferido y ve tu aplicación en acción. Deberías ser capaz de agregar y remover ítems de la lista de compras, y, gracias al LocalStorage, estos ítems se mantendrán incluso si haces un refresh en la página.

Aprovecha para probar la edición; en mi caso, agregué un listener para un doble clic en el ítem.

He dejado mi proyecto final para ti aquí en GitHub.

Próximos pasos

Bueno, ¡llegamos al final de esta jornada inicial por TypeScript! Es natural que, cuando ya tenemos un cierto conocimiento en JavaScript, podamos sentir cierta desconfianza en relación a TypeScript. Es como salir de la zona de confort, ¿no es así? Pero créeme, ¡es un paso que realmente vale la pena!

En proyectos más grandes, y especialmente en aquellos que no escribimos desde cero, TypeScript se convierte en un aliado invaluable. Nos ayuda a comprender cómo funcionan las cosas, previene una serie de errores comunes y facilita el mantenimiento del código.

Si te gustó esta introducción y quieres continuar profundizando en TypeScript, ¡tengo un gran consejo! Echa un vistazo a la formación sobre TypeScript aquí en Alura Latam. ¡En ella aprenderás aún más con el instructor Leonardo! Exploraremos muchos otros recursos y desafíos que este lenguaje tiene para ofrecer.

Y, claro, ¡recuerda seguirme en las redes sociales! Siempre estoy compartiendo consejos, insights y contenido valioso sobre frontend y otras tecnologías. ¡Es una excelente forma de continuar esta conversación y profundizar aún más en el conocimiento!

Estamos listos, espero que esta aventura haya sido de tu agrado. ¡Estoy emocionado por ver lo que vas a crear con TypeScript! Recuerda, el aprendizaje es continuo y cada nuevo desafío es una oportunidad de crecimiento.

Comparte tu lista de compras con el hashtag #aprendienalura y ¡etiquétame!

¡Larga vida y prosperidad!

Este artículo fue traducido y adaptado por Ingrid Silva

perfil-instructor

Vinicios Neves Vinicios es ingeniero de software, involucrado en la arquitectura, diseño e implementación de microservicios, micro frontends y sistemas distribuidos. Tiene experiencia significativa en aplicaciones, integración y arquitectura corporativa. Es Ingeniero de Software por la UNESA y Arquitecto de Software por la PUC Minas.

Navegación

  • Planes
  • Instructores
  • Blog
  • Política de privacidad
  • Términos de uso
  • Sobre nosotros
  • Preguntas frecuentes

¡CONTÁCTANOS!

  • ¡Quiero entrar en contacto!

Blog

  • Programación
  • Data Science
  • Front End
  • Innovación y Gestión
  • DevOps

AOVS Sistemas de Informática S.A CNPJ 05.555.382/0001-33

SÍGUENOS EN NUESTRAS REDES SOCIALES

YouTube Facebook Instagram Linkedin Whatsapp Spotify

NOVEDADES Y LANZAMIENTOS

Aliados

  • Programa de aceleração Scale-Up Endeavor
  • En Alura somos unas de las Scale-Ups seleccionadas por Endeavor, programa de aceleración de las empresas que más crecen en el país.
  • Growth Academy 2021 do Google For Startups
  • Fuimos unas de las 7 startups seleccionadas por Google For Startups en participar del programa Growth Academy en 2021
Alura

Powered by

Caelum

AOVS Sistemas de Informática S.A CNPJ 05.555.382/0001-33

SÍGUENOS EN NUESTRAS REDES SOCIALES

YouTube Facebook Instagram Linkedin Whatsapp Spotify

Cursos

Cursos de Programación
Lógica de Programación | Java
Cursos de Front End
HTML y CSS | JavaScript | React
Cursos de Data Science
Data Science | Machine Learning | Excel | Base de Datos | Data Visualization | Estadística
Cursos de DevOps
Docker | Linux
Cursos de Innovación y Gestión
Transformación Ágil | Marketing Analytics

Alura

  • Educação em Tecnologia

    • logo fiap FIAP
    • logo casa do codigo Casa do Código
    • logo pm3 PM3 - Cursos de Produto
  • Mais Alura

    • logo alura start START BY Alura
    • logo alura lingua Alura Língua
    • logo alura para empresas Alura Para Empresas
    • logo alura latam Alura LATAM
  • Comunidade

    • logo tech guide Tech Guide
    • logo 7 days of code 7 days of code
    • logo Hipsters ponto Jobs Hipsters ponto Jobs
  • Podcasts

    • logo Hipster Network Hipster Network
    • logo Hipsters ponto Tech Hipsters ponto Tech
    • logo Dev sem fronteiras Dev sem Fronteiras
    • logo Like a Boss Like a Boss
    • logo IA Sob Controle IA Sob Controle
    • logo Mesa de Produto Mesa de Produto
    • logo Decode Decode
    • logo FIAPCast FIAPCast