Introducción
TypeScript es un lenguaje de programación de propósito general utilizado en diversos entornos de desarrollo. A lo largo de los años desde su lanzamiento, ha ganado un gran apoyo de desarrolladores y empresas, como lo demuestra la clasificación de GitHub como el cuarto lenguaje de programación más utilizado en 2022. Desde entonces, la relevancia de TypeScript ha crecido.
Además, su popularidad se refleja en la abundancia de oportunidades laborales, con más de 20.000 puestos de trabajo relacionados con TypeScript anunciados en LinkedIn y los principales actores de la industria, incluidos Trivago y Stripe, que optan por migrar sus pilas de tecnología a TypeScript.
En este artículo, exploraremos TypeScript desde cero para comprender sus beneficios que han llevado a su uso cada vez mayor en la comunidad de desarrolladores.
TypeScript frente a JavaScript
TypeScript no es del todo nuevo. Es un superconjunto de JavaScript que aborda las limitaciones de este último. Como superconjunto, TypeScript extiende JavaScript añadiendo tipado estático.
Esta tipificación estática se puede declarar de dos maneras comunes:
1. Anotaciones de tipo
Esto implica especificar inmediatamente las variables y sus tipos la primera vez que se declaran. Así:
let name: string = "HygraphDonde nombre es el nombre de la variable y cadena es su tipo.
2. Alias de tipo
Este método implica definir un tipo por separado utilizando la palabra clave type y luego usarlo para anotar variables.
type StringType = {
name: string;
};
let name: StringType = { name: "Hygraph" };Ahora, echemos un vistazo a algunas de las características que ofrece TypeScript.
Principales características de TypeScript
Tipado estático
La tipificación estática se refiere a cuando las variables se declaran explícitamente con sus tipos de datos (como entero, cadena, booleano) en el momento de la compilación y el sistema realiza una verificación de tipo antes de ejecutar el programa.
Si bien el siguiente comportamiento está permitido en JavaScript, hacer lo mismo en TypeScript provocará un error debido a la implementación del tipo TypeScript.
let name: string = "hygraph";
name = 2000Escritura opcional
Si bien TypeScript permite la declaración explícita de variables, también permite escribir código similar a JavaScript sin declarar tipos. TypeScript infiere el tipo de forma predeterminada. Por ejemplo,
let name = "Hygraph";Arriba, TypeScript infiere que el nombre del tipo es una cadena a través del valor de inicialización de la variable, por ejemplo, “Hygraph”.
Genéricos de TypeScript
Al parametrizar tipos y funciones, los genéricos de TypeScript crean componentes y funciones reutilizables que pueden trabajar con diferentes tipos sin comprometer la seguridad de los tipos:
// Generic function to return the length of an array
function getArrayLength<T>(array: T[]): number {
return array.length;
}
// Using the generic function with different types of arrays
const stringArray: string[] = ["apple", "banana", "orange"];
const numberArray: number[] = [1, 2, 3, 4, 5];
console.log(getArrayLength(stringArray)); // Output: 3
console.log(getArrayLength(numberArray)); // Output: 5Los genéricos generalmente son útiles para definir tipos de datos personalizados que necesitan trabajar con tipos de datos como árboles, gráficos y colas.
Sistema de tipos avanzado
El sistema de tipos TypeScript va más allá de la tipificación estática básica. También ofrece funciones para definir tipos complejos, manipularlos, establecer relaciones entre variables, aplicar restricciones de tipo y otras funciones que permiten el desarrollo de aplicaciones sin errores.
Consideremos algunos de los tipos avanzados más utilizados.
1. Tipos de Unión
En TypeScript, la unión se refiere a declarar un argumento de variable o función que contiene múltiples tipos de datos. Esto puede ser útil cuando un valor tiene diferentes tipos de datos en tiempo de ejecución.
Los tipos de unión se representan con el símbolo |, que separa los tipos de datos. Por ejemplo:
let age = number | string;
age = 10;
age = "ten";Como se vio anteriormente, podemos especificar que la variable edad puede tener dos tipos de datos. Esto proporciona flexibilidad sin comprometer la seguridad de tipos.
2. Tipos de intersecciones
Los cruces permiten crear un nuevo tipo combinando varios tipos existentes en uno nuevo. Este nuevo tipo posee las propiedades y funciones de los tipos combinados.
Las intersecciones se crean utilizando el símbolo & entre los tipos que se van a combinar. Por ejemplo:
interface User {
id: number;
username: string;
email: string;
}
interface Admin {
isAdmin: boolean;
}
// A new type using intersection type
type UserAndAdmin = User & Admin;Aquí, el tipo User AndAdmin combina características tanto de la UI como de Admin para producir un tipo que requiere todas las características de ambos.
3. Tipos condicionales
Los tipos condicionales en TypeScript crean tipos que dependen de un estado, lo que permite la definición de tipos dinámicos que cambian según las propiedades, los valores u otro contexto del tipo.
Consideremos un ejemplo básico:
// A conditional type to determine if a type is an array
type IsArray<T> = T extends any[] ? true : false;
// Test the conditional type with different types
type Result1 = IsArray<number>; // false
type Result2 = IsArray<string[]>; // true
type Result3 = IsArray<boolean | []>; // trueLos tipos condicionales se definen mediante el operador ternario (? 🙂) entre corchetes angulares (<>), conocido como “parámetro de tipo genérico”; hablaremos de ello más adelante en este artículo. También utilizan la palabra clave extends, que comprueba si un tipo cumple una condición y genera otro tipo según el resultado de dicha condición.
4. Tipos de asignaciones
Los tipos mapeados en TypeScript permiten crear nuevos tipos mediante la conversión de propiedades de tipos existentes. Esto se logra iterando sobre las propiedades de un tipo fuente y aplicando una conversión a cada propiedad para generar un nuevo tipo. Por ejemplo:
// type representing a user
type User = {
id: number;
username: string;
email: string;
};
// Mapped type to make all properties optional
type OptionalUser = { [P in keyof User]?: User[P] };
// New type using the mapped type
const optionalUser: OptionalUser = { id: 1 };
// Property 'email' is now optional
optionalUser.username = "john_doe";
// Property 'id' is still required
// optionalUser.email = "[email protected]"; // Error: Property 'email' is missingLos tipos mapeados se definen mediante la sintaxis {[P in keyof Type]: NewType}, donde Type es el tipo de origen, P es la clave de propiedad y NewType es el tipo convertido. P itera sobre las claves de propiedad y define la transformación.
5. Escribe el apodo
Los alias de tipo permiten crear nombres personalizados (alias) para tipos de TypeScript existentes, incluyendo primitivos, tipos de unión, tipos de intersección e incluso tipos más complejos, como literales de objeto y tipos de función. Un alias de tipo se define con la palabra clave type seguida del nuevo nombre, como se muestra a continuación:
// type alias for a union type
type Result = "success" | "error";
// type alias for an object literal
type Point = { x: number; y: number };
// type alias for a function type
type Greeting = (name: string) => string;
// Using the type aliases
const status: Result = "success";
const origin: Point = { x: 0, y: 0 };
const greet: Greeting = (name) => Hello, ${name}!;El código anterior muestra los diferentes usos de los alias de tipo para diferentes tipos en TypeScript y su uso después de la declaración.
TypeScript en la programación orientada a objetos (POO)
OOP es un paradigma basado en el concepto de "objetos" que interactúan para crear código mantenible y reutilizable.
1. Clases de TypeScript
Las clases son patrones o diseños para crear objetos, es decir, definen datos (propiedades) y métodos (funciones).
Aquí hay un ejemplo de cómo implementar una clase en TypeScript:
class Organization {
private name: string;
private yearFounded: number;
constructor(name: string, yearFounded: number) {
this.name = name;
this.yearFounded = yearFounded;
}
public getDetails(): string {
return `${this.name} was founded in ${this.yearFounded}.`;
}
}
let organization = new Organization("Hygraph", 2015);
console.log(organization.name); // Error: Property 'name' is private and only accessible within class 'Organization'.
console.log(organization.getDetails()); // Output: Hygraph was founded in 2015En el código anterior, creamos una clase Organización con propiedades privadas denominadas y yearFounded, a las que solo se puede acceder y modificar dentro de la clase "Organización". Observe cómo se tipifican las propiedades y los métodos.
2. Interfaz de TypeScript
Las interfaces describen la forma de los objetos enumerando las propiedades y los métodos que deben tener, sin proporcionar detalles de implementación:
// Interface representing form data
interface FormData {
firstName: string;
lastName: string;
email: string;
age: number;
}
// Usage
let formData: FormData = {
firstName: "John",
lastName: "Doe",
email: "[email protected]",
age: 30
};En el ejemplo anterior, definimos una interfaz FormData que representa la estructura de los datos del formulario.
A continuación, creamos un objeto formData con propiedades relacionadas con la definición de la interfaz.
Números de TypeScript
Los tipos enumerados, representados por enum en TypeScript, son una colección de constantes nombradas encerradas entre llaves {}, donde cada constante tiene un valor numérico o de cadena asociado.
Una colección de listas típica de TypeScript podría verse así:
// enum for days of the week
enum DayOfWeek {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
enum HTTPStatusCodes {
OK = 200,
BadRequest = 400,
NotFound = 404,
}El bloque de código anterior explica inmediatamente lo que está sucediendo y demuestra el beneficio semántico de agregar significado al usar enumeraciones de TypeScript.
TypeScript y ES6
TypeScript es compatible con muchas de las características de ECMAScript 6 (ES6), también conocido como ECMAScript 2015. Algunas de estas características incluyen:
1) Funciones de flecha: A diferencia de las expresiones de función tradicionales, las funciones de flecha proporcionan una sintaxis sencilla para definir funciones. Ofrecen retorno implícito para expresiones de una sola línea y encadenamiento automático, y pueden ser útiles para funciones de devolución de llamada o de manejo de eventos.
// Arrow function
const add = (x, y) => x + y;
// Traditional function expression
const add = function(x, y) {
return x + y;
};2) Alfabeto de plantilla: Permite incrustar expresiones y cadenas de varias líneas directamente en el código entre llaves (“). Esto facilita la creación de cadenas dinámicas, incluyendo la interpolación de variables y expresiones.
const name: string = "John";
const greeting: string = `Hello, ${name}!`;Hay más funciones de ES6 de las que este artículo puede cubrir. Para más información, consulte ECMA International.
Ventajas de TypeScript sobre JavaScript
Desde que se lanzó TypeScript hace más de una década, ha habido un debate constante sobre sus ventajas sobre JavaScript.
En esta sección examinaremos algunos de estos beneficios.
- Tipo de seguridad: El sistema de tipos estáticos de TypeScript aplica anotaciones de tipos a variables, funciones y objetos, lo que ayuda con la detección temprana de errores y mejora la capacidad de mantenimiento a través de interfaces, clases y módulos.
- Mejor experiencia para desarrolladores: Los desarrolladores ahora pueden escribir código con mayor confianza, sabiendo que el compilador detectará posibles discrepancias de tipos antes de que el código llegue al tiempo de ejecución. Esto puede ser especialmente útil al migrar código JavaScript a TypeScript.
Cuándo usar TypeScript
De las ventajas y desventajas mencionadas anteriormente, se puede inferir que TypeScript podría no ser la mejor opción para todos los proyectos. Puede que sea cierto, pero ¿por qué dejar esa decisión en tus manos? Permítenos ayudarte a tomar una mejor decisión.
¿Cuándo es apropiado utilizar TypeScript?
- Aplicaciones a gran escala: TypeScript se desarrolló para abordar los problemas de escalabilidad de grandes bases de código JavaScript. A medida que el proyecto crece, la tipificación estática ayuda a detectar errores con antelación, lo que mejora la mantenibilidad del código y la colaboración entre los miembros del equipo.
- Trabajo en equipo: En un entorno de equipo con múltiples desarrolladores que contribuyen a una base de código, TypeScript puede facilitar la colaboración al imponer convenciones de codificación y mejorar la comunicación a través de código autodocumentado.
- Proyectos a largo plazo: El mantenimiento es la última etapa del ciclo de vida del desarrollo de software y puede durar una década o tan solo un año. TypeScript es adecuado para proyectos a largo plazo donde la mantenibilidad, la escalabilidad y la preparación del código para el futuro son consideraciones esenciales.
Cuándo no usar TypeScript
Desafortunadamente, a pesar de sus beneficios, TypeScript puede no ser adecuado para todos los casos de uso. Por ejemplo:
- Proyectos sencillos: Para proyectos pequeños con una complejidad mínima, los beneficios de la tipificación estática y las herramientas avanzadas pueden no superar la configuración y la curva de aprendizaje asociadas con TypeScript.
- Bases de código antiguas: Convertir grandes bases de código JavaScript existentes a TypeScript puede ser abrumador. En estos casos, el esfuerzo necesario para migrar a TypeScript puede no justificar los beneficios, especialmente si el proyecto está llegando al final de su vida útil o requiere un mantenimiento mínimo.









