JavaScript es el lenguaje de programación más utilizado para el desarrollo web. Pero carece de soporte para la verificación de tipos, que es una característica esencial de los lenguajes de programación modernos.

JavaScript fue diseñado originalmente como un lenguaje de secuencias de comandos simple. Su naturaleza laxa y la ausencia de características cruciales de la programación orientada a objetos plantean ciertos desafíos para los desarrolladores:

  1. Documentación y autocompletado limitados.

  2. Incapacidad para utilizar conceptos de POO.

  3. Falta de seguridad de tipos, lo que lleva a errores en tiempo de ejecución.

  4. Desafíos en la refactorización y el mantenimiento.

  5. Ausencia de interfaces y puntos de integración.

TypeScript resuelve estos problemas. Fue diseñado para hacer de JavaScript un lenguaje de programación moderno más perfecto. Ayuda a mejorar la experiencia del desarrollador, ofrece muchas características útiles y mejora la interoperabilidad.

Este artículo se adentra en los conceptos básicos de TypeScript. Te enseñaré cómo instalar TS y configurar un proyecto. Luego cubriremos algunos fundamentos importantes. También aprenderás cómo TypeScript se compila a JavaScript, lo que lo hace compatible con navegadores y entornos Node.js.

Lo que cubriremos:

Requisitos

Antes de adentrarte en TypeScript, es importante tener una comprensión fundamental de ciertos conceptos para garantizar un aprendizaje más fluido. Si bien TypeScript mejora JavaScript con tipado estático y otras características poderosas, se basa en principios básicos de JavaScript. Esto es lo que debes saber:

1. Fundamentos de JavaScript

TypeScript es un superset de JavaScript, lo que significa que extiende las capacidades de JavaScript. Para aprender TypeScript de manera efectiva, primero debes tener un sólido entendimiento de los conceptos básicos de JavaScript, que incluyen:

  • Sintaxis y tipos de datos: Comprende cómo declarar variables (let, const y var), trabajar con tipos primitivos (cadenas, números, booleanos) y manejar arreglos y objetos.

  • Flujo de control: Estar familiarizado con bucles (for, while), condicionales (if-else, switch) y cómo controlan la ejecución del programa.

  • Funciones: Saber cómo definir e invocar funciones, trabajar con parámetros, valores de retorno, y entender conceptos como funciones flecha y cierres.

  • Programación Orientada a Objetos (OOP): Aprender sobre la creación y trabajo con objetos, clases, y herencia. Las características basadas en clases de TypeScript se basan en gran medida en el modelo OOP de JavaScript.

  • Manejo de errores: Entender cómo utilizar bloques try-catch para manejar errores en tiempo de ejecución.

2. HTML y CSS básicos

Aunque TypeScript es un lenguaje utilizado principalmente con JavaScript, tener un entendimiento básico de HTML y CSS es útil, especialmente para desarrolladores front-end. Esto se debe a que la mayoría de los proyectos de TypeScript implican la creación o trabajo con aplicaciones web

  • HTML: Entender cómo estructurar páginas web usando etiquetas, atributos, y elementos.

  • CSS: Aprender a estilizar elementos utilizando selectores, propiedades y valores. Tener familiaridad con frameworks de CSS como Bootstrap es un plus.

3. Familiaridad con Herramientas de Desarrollo

  • Un editor de código como Visual Studio Code, que tiene un excelente soporte para TypeScript y extensiones.

  • Node.js y npm: Entender cómo configurar un entorno de desarrollo, ejecutar JavaScript fuera del navegador y usar npm (Node Package Manager) para instalar dependencias.

  • Control de versiones (Git): Aprender los conceptos básicos de Git para rastrear cambios y colaborar de manera efectiva en proyectos de TypeScript.

Comenzando – Cómo instalar TypeScript

Para empezar a trabajar con TypeScript, necesitarás instalarlo. No es un proceso complicado. Una vez instalado TypeScript, podrás aprovechar su potencia para crear soluciones de alta calidad.

Puedes instalar TS de dos maneras:

  1. Instalación Global: te permite acceder al compilador desde cualquier directorio en tu máquina. Para instalar TypeScript globalmente, ejecuta el siguiente comando:
npm install -g typescript

Este comando utiliza el gestor de paquetes de Node.js, npm. Instala TypeScript de forma global, permitiendo que el comando esté disponible en la línea de comandos.

  1. Instalación Local: en este caso, TypeScript se instala únicamente en un proyecto específico. Este método garantiza la compatibilidad de versiones y la consistencia entre los miembros del equipo. Para instalar TypeScript localmente, ejecuta el siguiente comando:
npm install typescript --save-dev

A diferencia de la instalación global, este comando instala TypeScript como una dependencia de desarrollo. El comando tsc solo está disponible para uso específico del proyecto, es decir, en el proyecto donde ejecutas el comando.

¿Puedes instalar TypeScript sin problemas ahora? ¡Espero que sí!

Cómo Organizar tus Proyectos TypeScript

Organizar un proyecto TypeScript implica estructurar sus archivos con nombres y directorios significativos, separar responsabilidades y utilizar módulos para encapsulación y reutilización.

La extensión .ts denota archivos de TypeScript y contiene código que se convierte en JavaScript para su ejecución.

TypeScript también admite archivos .d.ts, también conocidos como archivos de definición de tipos. Estos archivos ofrecen información de tipo sobre bibliotecas o módulos externos de JavaScript, ayudando en una mejor verificación de tipos y autocompletado del código, así como mejorando la eficiencia del desarrollo. A continuación se muestra un ejemplo de una buena estructura de proyecto TS:

my-ts-project/
├── src/ 
│   ├── components/ 
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Modal.tsx
│   ├── services/ 
│   │   ├── api.ts
│   │   └── authService.ts
│   ├── utils/ 
│   │   ├── helpers.ts 
│   │   └── validators.ts
│   ├── models/ 
│   │   ├── User.ts
│   │   └── Product.ts
│   ├── index.tsx 
│   └── styles/ 
│       ├── global.css
│       └── theme.css
├── public/ 
│   ├── index.html
│   └── assets/ 
│       ├── images/
│       └── fonts/
├── tsconfig.json
└── package.json

Entendamos qué está sucediendo aquí:

  1. src/: Este directorio alberga todo el código fuente del proyecto.

    • components/: Contiene componentes de UI reutilizables (por ejemplo, Button, Input, Modal). Usar .tsx (TypeScript JSX) permite escribir JSX con seguridad de tipos.

    • services/: Contiene servicios que interactúan con APIs externas o manejan la lógica de la aplicación (por ejemplo, api.ts para llamadas a la API, authService.ts para autenticación).

    • utils/: Contiene funciones auxiliares y clases de utilidad para tareas comunes (por ejemplo, helpers.ts para formateo de fechas, validators.ts para validación de entradas).

    • models/: Define interfaces o clases de TypeScript para representar estructuras de datos (por ejemplo, User.ts, Product.ts).

    • index.tsx: El punto de entrada principal de la aplicación.

    • styles/: Contiene archivos CSS u otros archivos de estilo.

  2. public/: Este directorio contiene activos estáticos que no son procesados por TypeScript (por ejemplo, HTML, imágenes, fuentes).

  3. tsconfig.json: Archivo de configuración de TypeScript, que especifica las opciones del compilador.

  4. package.json: Archivo de manifiesto del proyecto, que enumera dependencias, scripts y otros metadatos del proyecto.

Solo una nota rápida sobre las convenciones de nombres para que las entiendas aquí:

  • Usa PascalCase para los nombres de clases (por ejemplo, User, Product).

  • Usa camelCase para los nombres de funciones y variables (por ejemplo, getUser, firstName).

  • Utilice nombres significativos y descriptivos para archivos y directorios.

Esta estructura promueve la modularidad, la reutilización y una mejor organización, lo que hace que sus proyectos de TypeScript sean más fáciles de mantener y escalar.

Organizar correctamente sus proyectos de TS mejora la mantenibilidad del código, la legibilidad y la colaboración en los flujos de trabajo de desarrollo de TypeScript.

Cómo Funcionan las Tipificaciones en TypeScript

Como cualquier otro lenguaje de programación tipado, TypeScript se basa en definiciones de tipo, generalmente llamadas Tipificaciones.

La tipificación es un término utilizado en programación para definir tipos de datos para variables, parámetros de métodos y valores de retorno dentro del código.

La tipificación le permite detectar errores rápidamente y temprano en el desarrollo, un superpoder que ayuda a mantener una mejor calidad de código.

Para especificar un tipo en TypeScript, coloque dos puntos (:) y el tipo de datos deseado después del nombre de su variable. Aquí hay un ejemplo:

let age: number = 2;

La variable anterior está declarada con el tipo number. En TypeScript, esto significa que solo puede almacenar números y nada más.

Técnicas de Tipificación

En TypeScript, los datos se pueden tipificar de dos formas principales:

  1. Tipificación Estática: La tipificación estática se refiere a especificar explícitamente el tipo de datos de variables y otras entidades en el código durante el desarrollo. El compilador de TypeScript hace cumplir estas definiciones de tipo, lo que ayuda a detectar errores relacionados con el tipo temprano. Por ejemplo:
let age: number = 25;

Aquí, la variable age está declarada explícitamente como tener el tipo number. Esto asegura que solo se puedan asignar valores numéricos a ella, reduciendo el riesgo de errores en tiempo de ejecución.

  1. Tipeado Dinámico: El tipeado dinámico en TypeScript se refiere a escenarios donde el tipo de una variable se determina en tiempo de ejecución. Esto puede ocurrir cuando las variables se les asigna el tipo any, lo que les permite contener valores de cualquier tipo. TypeScript no realiza verificación de tipos en operaciones que involucran variables con el tipo any.
let value: any;
value = 25; // Número
value = "Hello"; // Cadena

Aunque TypeScript es principalmente un lenguaje de tipado estático, el tipeado dinámico aún puede ser útil en casos específicos, como:

  • Trabajar con bibliotecas de terceros que carecen de definiciones de tipos.

  • Interactuar con datos estructurados de forma dinámica (por ejemplo, respuestas JSON de APIs con estructuras desconocidas).

  • Prototipado rápido o cuando la información de tipo no está disponible durante la fase inicial de desarrollo.

Tipeado Estático vs. Dinámico en TypeScript

La escritura estática es significativamente más común en TypeScript, ya que es una de las características principales que diferencia a TypeScript de JavaScript. Al hacer cumplir controles estrictos de tipo, la escritura estática mejora la mantenibilidad del código, reduce errores y aumenta la productividad del desarrollador.

La escritura dinámica se reserva típicamente para casos donde se requiere flexibilidad o al tratar con datos cuya estructura no se puede determinar de antemano. Solo ten en cuenta que depender en gran medida de la escritura dinámica (por ejemplo, abusar del tipo any) generalmente no se recomienda, ya que socava los beneficios del sistema de escritura estática de TypeScript.

Entonces, si bien la escritura dinámica tiene su lugar en ciertos casos excepcionales, la escritura estática es el enfoque preferido y más comúnmente utilizado en el desarrollo de TypeScript.

Inferencia de Tipos y Tipos de Unión

Inferencia de Tipos

La inferencia de tipos es una característica poderosa de TypeScript que permite al compilador deducir automáticamente el tipo de una variable basándose en el valor asignado durante la inicialización. En términos más simples, TypeScript analiza el valor que asignas a una variable y decide qué tipo debería ser, incluso si no declaras explícitamente el tipo.

Por ejemplo:

typescriptCopyEditlet age = 25; // TypeScript infiere que 'age' es de tipo 'number'
age = "hello"; // Error: El tipo 'string' no es asignable al tipo 'number'

En este ejemplo, la variable age se infiere automáticamente como un número debido a su valor inicial, 25. Cualquier intento de reasignar age a un valor de un tipo diferente (como una cadena) resultará en un error de tipo.

La inferencia de tipos es particularmente útil porque reduce la necesidad de anotaciones de tipo explícitas, haciendo que tu código sea más limpio y legible. Sin embargo, aún proporciona la seguridad y confiabilidad de la verificación de tipos de TypeScript.

Cuándo usar la inferencia de tipos:
  • Asignaciones simples: Utiliza la inferencia de tipos para asignaciones sencillas donde el tipo es obvio a partir del valor.

  • Valores predeterminados: Al proporcionar valores predeterminados para variables o parámetros de función, la inferencia de tipos asegura que se aplique el tipo correcto sin requerir anotaciones manuales.

  • Prototipado rápido: Durante las primeras etapas del desarrollo, la inferencia de tipos puede reducir el código repetitivo mientras todavía se aplica la seguridad de tipos.

Tipos de unión

Los tipos de unión permiten que una variable contenga valores de múltiples tipos. Se definen colocando una barra vertical (|) entre los tipos. Esta característica es particularmente útil cuando una variable puede legítimamente tener más de un tipo durante su ciclo de vida.

Por ejemplo:

typescriptCopyEditlet numOrString: number | string; // 'numOrString' puede contener ya sea un número o una cadena
numOrString = 25; // Válido
numOrString = "hello"; // Válido
numOrString = true; // Error: El tipo 'boolean' no se puede asignar al tipo 'number | string'

Incluso puedes definir tipos de unión con más de dos tipos posibles:

typescriptCopyEditlet multiType: number | string | boolean;
multiType = 42; // Válido
multiType = "TypeScript"; // Válido
multiType = false; // Válido
Cuándo usar tipos de unión:
  • Parámetros de función flexibles: Cuando una función puede aceptar múltiples tipos de entrada.

      typescriptCopyEditfunction printValue(value: string | number) {
        console.log(value);
      }
    
  • Manejo de estructuras de datos diversas: Cuando se trabaja con API o fuentes de datos externas donde los campos pueden variar en tipo.

  • Variables opcionales o de múltiples estados: Por ejemplo, una variable que puede representar un estado de carga como un booleano, un error como una cadena, o datos válidos como un objeto:

      typescriptCopyEditlet status: boolean | string | { success: boolean; data: any };
    

Cómo manejar objetos, arrays y tipos de funciones en TypeScript

Para dominar TypeScript, debes comprender los diversos tipos de datos admitidos en TypeScript y cómo y cuándo usarlos.

Los tipos primitivos de JavaScript como cadenas, números, booleanos y más también definen los bloques fundamentales de datos en TypeScript. Pero en particular, los Objetos, Arrays, y Funciones son esenciales para construir aplicaciones sólidas. Con objetos, arrays y funciones, puedes manejar mejor los datos y utilizarlos eficientemente en el desarrollo.

Tipos de Objetos en TypeScript

Los tipos de objetos representan el diseño para crear objetos en TypeScript. Puedes usar objetos para definir su forma, similar a cómo se usan las clases en la programación orientada a objetos (OOP). Pero los objetos carecen de los aspectos de comportamiento y encapsulación que ofrecen las clases.

Para definir un tipo de objeto, define explícitamente el diseño del objeto después de los dos puntos (:). Por ejemplo:

// Inicialización del Tipo de Objeto

let student: {
    name: string;
    age: number;
    matricNumber: string | number;
 };

// Asignación del Objeto con datos reales

student = {
    name: "Akande"
    age: 21,
    matricNumber: 21/52 + "HP" + 19,
};

Observa que las propiedades terminan con un punto y coma; en lugar de una coma , que las finaliza en un objeto real.

La anterior es la forma principal de definir un objeto en TypeScript. Otra forma es usar interfaces, las cuales cubriré más adelante en este artículo.

Tipos de Arrays en TypeScript

Los arrays en TypeScript te permiten almacenar múltiples valores del mismo o diferentes tipos de datos en una sola variable. Mejoran la seguridad y claridad de tu código al hacer cumplir la consistencia de tipos en los elementos del array.

En TypeScript, los tipos de arrays se pueden definir de dos formas:

1. Utilizando el modelo Array<tipo>

Esta sintaxis utiliza el tipo genérico Array, donde tipo representa el tipo de elementos que puede contener el array.

typescriptCopyEditlet numbers: Array<number> = [1, 2, 3, 4, 5];
let mixedArray: Array<number | string> = [1, 2, 3, 4, 5, "Hello"];
  • Ejemplo de números: Este array solo puede contener números. Intentar añadir un string u otro tipo a este array resultará en un error de tipo.

      typescriptCopyEditnúmeros.push(6); // Válido
      números.push("Hola"); // Error: El tipo 'string' no es asignable al tipo 'number'
    
  • mixedArray Ejemplo: Este arreglo utiliza un tipo de unión (number | string), lo que le permite almacenar tanto números como cadenas.

      typescriptCopyEditmixedArray.push(42); // Válido
      mixedArray.push("TypeScript"); // Válido
      mixedArray.push(true); // Error: El tipo 'boolean' no se puede asignar al tipo 'number | string'
    

2. Usando el type[] modelo

Esta sintaxis añade corchetes ([]) al tipo de elementos que el arreglo puede contener.

typescriptCopyEditconst numbers: number[] = [1, 2, 3, 4, 5];
const mixedArray: (string | number)[] = [1, 2, 3, 4, 5, "Hello"];
  • números Ejemplo: Similar al ejemplo de Array<número>, este arreglo solo puede contener números.

      typescriptCopyEditnúmeros[0] = 10; // Válido
      números.push("Hola"); // Error: El tipo 'cadena' no se puede asignar al tipo 'número'
    
  • mixedArray Ejemplo: Al igual que el mixedArray anterior, este array permite tanto números como cadenas, proporcionando flexibilidad donde el tipo de datos puede variar.

      typescriptCopyEditmixedArray[1] = "Mundo"; // Válido
      mixedArray.push(true); // Error: El tipo 'boolean' no es asignable al tipo 'string | number'
    

Cómo usar Arrays en TypeScript

Los arrays son versátiles y comúnmente utilizados para almacenar colecciones de datos relacionados. Aquí tienes algunos escenarios prácticos:

Almacenar Datos Homogéneos:
Cuando todos los elementos en el array comparten el mismo tipo, como una lista de IDs de usuario o precios de productos:

typescriptCopyEditconst userIds: number[] = [101, 102, 103];
const productPrices: Array<number> = [29.99, 49.99, 19.99];

Almacenamiento de Datos Heterogéneos:
Cuando los elementos pueden tener diferentes tipos, como una lista de mensajes que contienen texto y metadatos opcionales:

typescriptCopyEditconst messages: (string | object)[] = [
  "Welcome",
  { type: "error", text: "Something went wrong" },
];

Iterando Sobre Arrays:
Los arrays en TypeScript se pueden utilizar en bucles con total seguridad de tipos:

typescriptCopyEditconst scores: number[] = [80, 90, 70];
scores.forEach((score) => console.log(score + 5)); // Añade 5 a cada puntuación

Parámetros de Función y Tipos de Retorno:
Los arrays también se pueden pasar como parámetros de función o devolver por funciones con tipado estricto:

typescriptCopyEditfunction getNumbers(): number[] {
  return [1, 2, 3];
}
function printStrings(strings: string[]): void {
  strings.forEach((str) => console.log(str));
}

Tipos de Funciones en TypeScript

Los tipos de funciones en TypeScript describen la forma de las funciones, incluyendo los tipos de parámetros y tipos de retorno. Los tipos de funciones se definen especificando explícitamente los tipos de parámetros durante la declaración. El tipo de retorno se especifica añadiendo : y el tipo a retornar inmediatamente después de los corchetes. Por ejemplo:

function addition (a: number, b: number): number {
return a + b;
}

La función anterior recibe dos números, los suma y devuelve un número. La función no funcionará si alguno de sus argumentos no son números y si devuelve cualquier cosa que no sea un número. Por ejemplo:

  1. Llamando a la función con una cadena como argumento:
// Esto no funcionará porque espera números, y uno de los argumentos es una cadena

addition(1, "two");
  1. Reescribiendo la función para devolver una cadena:
// La función devolverá un error porque está retornando una cadena

function addition (a: number, b: number): string {
    let result = a + b;
    let returnStatement = `Addition of ${a} and ${b} is: ${result}`;
    return returnStatement;
}

Prueba el código por ti mismo para ver cómo funcionan estos ejemplos.

Entender y manejar eficazmente objetos, arrays y funciones en TypeScript te permite escribir código seguro y mantenible, mejorando la fiabilidad y escalabilidad de tus aplicaciones.

Cómo crear tipos personalizados en TypeScript

A menudo, tu patrón de diseño no sigue los tipos de datos integrados en TypeScript. Por ejemplo, es posible que tengas patrones que usen programación dinámica, lo que puede causar problemas en tu código. TypeScript ofrece una solución para crear tipos personalizados para abordar este problema.

Los tipos personalizados te permiten definir tu estructura de datos y formas según tus necesidades. Esto mejora la legibilidad y mantenibilidad del código.

La palabra clave Type

La palabra clave type te permite crear alias de tipos, proporcionando una forma de crear tipos personalizados. Los tipos que creas se pueden reutilizar en todo tu código. Los alias de tipos ayudan a definir tipos de unión o combinar tipos en un solo alias. La sintaxis para crear un tipo personalizado es la siguiente:

// Sintaxis

type TypeAlias = type;

Y aquí tienes un ejemplo:

El código anterior crea un tipo personalizado UserName, una unión de números y strings. Utiliza el tipo creado para definir dos variables relativamente para comprobar si el tipo funciona.

Ten en cuenta que se recomienda que un alias de tipo comience con una letra mayúscula.

La palabra clave Type se usa generalmente para primitivos, ¿pero cómo crear un tipo de objeto personalizado?

Aquí es donde entran en juego las Interfaces.

Interfaces de TypeScript

Las interfaces en TypeScript se utilizan para definir la estructura de objetos. Sirven como planos, especificando las propiedades que un objeto debe tener y sus respectivos tipos. Esto asegura que los objetos se ajusten a una forma consistente, lo que permite la seguridad de tipos y un código más claro.

Definir una interfaz

Una interfaz se define utilizando la palabra clave interface. La sintaxis se ve así:

typescriptCopyEditinterface InterfaceName {
  property1: Type;
  property2: Type;
}

Ejemplo:

typescriptCopyEditinterface User {
  id: number;
  name: string;
  email: string;
}

const user: User = {
  id: 1,
  name: "Alice",
  email: "[email protected]",
};

Esto es lo que sucede en este ejemplo:

  1. Declaración de la interfaz (interface User):

    • Aquí, definimos un plano para un objeto User. Especifica que cualquier objeto de tipo User debe tener las siguientes propiedades:

      • id de tipo number

      • name de tipo string

      • email de tipo string

  2. Usando la interfaz (const usuario: Usuario):

    • Declaramos un objeto usuario de tipo Usuario.

    • El objeto debe tener todas las propiedades definidas en la interfaz Usuario, con valores de los tipos especificados. Si falta una propiedad o su tipo no coincide, TypeScript generará un error en tiempo de compilación.

Por ejemplo:

    typescriptCopyEditconst invalidUser: User = {
      id: 1,
      name: "Alice",
      // Error: La propiedad 'correo electrónico' falta en el tipo
    };

Entonces, podrías estar preguntándote: ¿por qué deberías usar interfaces?

  • Seguridad de tipo: Asegura que los objetos se ajusten a la estructura esperada, previniendo errores en tiempo de ejecución.

  • Reusabilidad: La misma interfaz puede ser reutilizada en diferentes partes de la aplicación, reduciendo la duplicación.

  • Claridad del código: Hace que el código sea más fácil de leer y entender al describir explícitamente la forma de los objetos.

Características Avanzadas de las Interfaces

  1. Propiedades opcionales: Puedes hacer que las propiedades sean opcionales añadiendo un signo de interrogación (?).

     typescriptCopyEditinterface Product {
       id: number;
       name: string;
       description?: string; // Propiedad opcional
     }
    
     const product: Product = {
       id: 101,
       name: "Laptop",
     }; // Válido, ya que 'description' es opcional
    
  2. Propiedades de solo lectura: Usa readonly para evitar que las propiedades sean modificadas después de la inicialización.

     typescriptCopyEditinterface Point {
       readonly x: number;
       readonly y: number;
     }
    
     const point: Point = { x: 10, y: 20 };
     point.x = 15; // Error: No se puede asignar a 'x' porque es una propiedad de solo lectura
    
  3. Extender interfaces: Las interfaces pueden heredar propiedades de otras interfaces, lo que permite la composición.

     typescriptCopyEditinterface Persona {
       nombre: string;
       edad: number;
     }
    
     interface Empleado extiende Persona {
       idEmpleado: number;
     }
    
     const empleado: Empleado = {
       nombre: "John",
       edad: 30,
       idEmpleado: 1234,
     };
    

Cuándo Usar Interfaces

Hay varios escenarios en los que es una buena idea usar interfaces. Puedes utilizarlas cuando quieras definir y hacer cumplir la estructura de los objetos que se pasan en tu código.

También son útiles en las respuestas de API, ya que te ayudan a verificar tipos de objetos recibidos de las API. Esto asegura que los datos se ajusten a tus expectativas.

Las interfaces también son convenientes al trabajar con tipos reutilizables. Cuando múltiples partes de tu aplicación utilizan objetos con la misma estructura, las interfaces previenen la duplicación.

Al aprovechar las interfaces, puedes crear aplicaciones robustas, mantenibles y seguras en cuanto a tipos. Son una característica esencial de TypeScript que promueve un código limpio y predecible.

Genéricos y Tipos Literales

Los genéricos en TypeScript te permiten crear componentes reutilizables que pueden trabajar con varios tipos de datos. Te permiten escribir funciones, clases e interfaces sin especificar el tipo exacto de antemano, haciendo que tu código sea más flexible y mantenible.

A continuación, un ejemplo de una función genérica y una interfaz genérica en TypeScript:

// Interfaz genérica para una caja que puede contener cualquier valor 

interface  Box<T> { 
    value: T; 
}

// Ejemplos de uso

let  numberBox: Box<number> = { value: 10 };
let  stringBox: Box<string> = { value: "TypeScript" };

console.log(numberBox.value); // Salida: 10  
console.log(stringBox.value); // Salida: TypeScript

Puedes usar genéricos cuando no estás seguro de tu tipo de dato.

A diferencia de los Genéricos, los tipos literales te permiten especificar los valores exactos que una variable puede contener. Esto añade una mayor especificidad y seguridad de tipo a tu código, evitando que se asignen valores no deseados. Aquí tienes un ejemplo:

type Direction = 'up' | 'down' | 'left' | 'right';

Una variable creada con el tipo anterior solo puede ser asignada para las cadenas up, down, left y right.

En general, aprovechar los tipos personalizados en TypeScript te permite crear estructuras de datos expresivas, reutilizables y seguras, lo que te ayuda a desarrollar aplicaciones más robustas y mantenibles.

Cómo combinar tipos en TypeScript

Combinar tipos en TypeScript une múltiples declaraciones de tipo en un solo tipo unificado. Esta capacidad permite a los desarrolladores construir tipos complejos a partir de piezas más pequeñas y reutilizables, mejorando la claridad, reutilización y mantenibilidad del código.

1. Combinación de Declaraciones en Interfaces

TypeScript soporta la combinación de declaraciones, donde múltiples declaraciones de interfaces con el mismo nombre se combinan automáticamente en una sola interfaz. Esto te permite ampliar una interfaz existente definiendo propiedades o métodos adicionales.

Ejemplo:
typescriptCopyEditinterface User {
  id: number;
  name: string;
}

interface User {
  email: string;
}

const user: User = {
  id: 1,
  name: "Alice",
  email: "[email protected]",
};
Cómo funciona:
  • La interfaz User se declara dos veces, cada una con propiedades diferentes.

  • TypeScript fusiona automáticamente estas declaraciones en una sola interfaz:

      typescriptCopyEditinterface User {
        id: number;
        name: string;
        email: string;
      }
    
  • Al crear el objeto user, todas las propiedades de la interfaz fusionada deben estar presentes. Si falta alguna propiedad, TypeScript generará un error.

La fusión de declaraciones es particularmente útil al trabajar con bibliotecas de terceros. Puedes extender o agregar nuevas propiedades a una interfaz existente sin modificar el código fuente de la biblioteca.

2. Fusión de Interfaces Usando la palabra clave extends

La palabra clave extends permite que una interfaz herede propiedades y métodos de otra, creando una nueva interfaz que combina las propiedades de ambas.

Ejemplo:
typescriptCopyEditinterface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  employeeId: number;
}

const employee: Employee = {
  name: "John",
  age: 30,
  employeeId: 101,
};
Cómo funciona:
  • La interfaz Person define dos propiedades: name y age.

  • La interfaz Employee utiliza la palabra clave extends para heredar las propiedades de Person.

  • La interfaz Employee también añade una nueva propiedad, employeeId.

  • El objeto employee debe incluir todas las propiedades de Person y Employee.

Este enfoque es ideal para relaciones jerárquicas. Por ejemplo, puedes definir una interfaz base para propiedades compartidas y extenderla para tipos especializados.

3. Combinación de Tipos Usando el & Operador

El operador &, conocido como tipo de intersección, te permite combinar múltiples tipos en un solo tipo. El tipo resultante incluye todas las propiedades y métodos de cada tipo.

Ejemplo:
typescriptCopyEdittype Address = {
  city: string;
  country: string;
};

type ContactInfo = {
  email: string;
  phone: string;
};

type EmployeeDetails = Address & ContactInfo;

const employee: EmployeeDetails = {
  city: "New York",
  country: "USA",
  email: "[email protected]",
  phone: "123-456-7890",
};
Cómo funciona:
  • Address y ContactInfo son dos tipos separados.

  • DetallesEmpleado es un tipo de intersección creado usando Dirección & InformaciónContacto.

  • El objeto empleado debe incluir todas las propiedades tanto de Dirección como de InformaciónContacto. La ausencia de propiedades o propiedades escritas incorrectamente resultará en un error de TypeScript.

Los tipos de intersección son útiles cuando necesitas combinar tipos no relacionados o crear tipos compuestos para casos de uso específicos, como respuestas de API que fusionan diferentes estructuras de datos.

Cuándo usar cada uno de estos enfoques

  1. Fusión de declaraciones: Úsalo cuando quieras extender o aumentar una interfaz existente, especialmente en bibliotecas de terceros o bases de código compartidas.

  2. extends palabra clave: Úsalo para relaciones jerárquicas donde una interfaz base puede especializarse en tipos más específicos.

  3. Tipos de intersección (&): Úsalo cuando necesites combinar múltiples tipos no relacionados en un solo tipo para casos de uso específicos.

Al comprender estas técnicas de fusión y sus implicaciones, puedes estructurar tu código TypeScript de manera efectiva, mejorando la reutilización y mantenibilidad, mientras mantienes la seguridad de tipos.

Agrupamiento y transformaciones en TypeScript

No todos los navegadores admiten el último JavaScript utilizado por TypeScript. Por lo tanto, puedes utilizar el compilador de TypeScript, o tsc, para convertir el código TypeScript (.ts) en JavaScript convencional (.js) que es universalmente compatible con todos los navegadores. tsc traduce elementos específicos de TypeScript como tipos y clases en código JavaScript que los navegadores pueden interpretar.

Para ejecutar archivos TypeScript, tsc es tu opción. Puedes instalar tsc utilizando npm y luego transformar tus archivos .ts en archivos .js. Para usar tsc, solo especifica el nombre del archivo TypeScript antes del comando tsc. Por ejemplo, si tienes un archivo llamado app.ts, puedes ejecutarlo escribiendo:

tsc app.ts

Webpack o Parcel se emplean frecuentemente para desplegar código TypeScript en navegadores. Estas herramientas agrupan todos los archivos JavaScript, incluidos los de TypeScript, para mejorar el rendimiento y facilitar la implementación del sitio web. También optimizan la carga del código reduciendo su tamaño y mejorando la velocidad del navegador.

Construyendo un mejor código con TypeScript

Adoptar TypeScript como desarrollador de JavaScript abre posibilidades para escribir un código más robusto y mantenible. Al entender los conceptos básicos y fundamentales presentados en esta guía, puedes aprovechar el sistema de tipado estático de TypeScript para detectar errores temprano en el desarrollo, lo que lleva a menos bugs y un mantenimiento de código más fluido.

Al utilizar TypeScript, los desarrolladores de JavaScript pueden mejorar la calidad y productividad de su código. A medida que sigas explorando y practicando con TypeScript, descubrirás aún más características y funcionalidades poderosas.

Sigue desafiando tus límites y sumérgete más profundamente en el mundo de TypeScript. 😉