TypeScript

img

¿Qué es TypeScript?

TypeScript es un superset de JavaScript desarrollado por Microsoft que agrega tipado estático y características avanzadas al lenguaje.
Esto significa que todo código JavaScript válido también es válido en TypeScript, pero con la ventaja de detectar errores antes de ejecutar el programa gracias a su sistema de tipos.

Diferencias clave respecto a JavaScript:

2. ¿Para qué se usa?

TypeScript se utiliza principalmente para desarrollo a gran escala donde la mantenibilidad y la calidad del código son esenciales.

Contextos ideales:

3. ¿Qué puedo construir con TypeScript?

Con TypeScript puedes desarrollar prácticamente todo lo que se puede hacer con JavaScript, pero con mayor robustez y escalabilidad:

4. ¿Cuándo es más conveniente usarlo?

TypeScript es especialmente útil en situaciones donde:

⚠️ En proyectos pequeños, prototipos o scripts simples, puede ser excesivo usar TypeScript debido a la configuración y compilación necesarias.

Buenas prácticas recomendadas

Buenas prácticas

Patrones recomendados


Resumen rápido

✅ Fortalezas principales:

⚠️ Debilidades principales:

🛠️ Cuándo usarlo:

🚫 Cuándo evitarlo:


Temas


Conceptos relacionados

Antes de comenzar a trabajar con TypeScript, es importante comprender algunos conceptos clave que te ayudarán a sacarle el máximo provecho al lenguaje.

1. JavaScript

TypeScript es un superset de JavaScript, por lo que debes conocer:

⚠️ Sin una base sólida de JavaScript, aprender TypeScript será más complicado.

2. Tipado Estático

El tipado estático es la base de TypeScript.
Permite definir y validar el tipo de datos en tiempo de desarrollo.

Ejemplo:

let edad: number = 25;
edad = "veinticinco"; // ❌ Error: no se puede asignar string a number

Beneficios:

3. Interfaces y Tipos

Permiten definir la forma de objetos y estructurar mejor el código.

Ejemplo con interface:

interface Usuario {
  id: number;
  nombre: string;
  activo: boolean;
}

const user: Usuario = {
  id: 1,
  nombre: "Fernando",
  activo: true,
};

4. Orientación a Objetos (POO)

TypeScript tiene soporte completo para POO:

Ejemplo:

class Animal {
  constructor(public nombre: string) {}

  hacerSonido(): void {
    console.log(`${this.nombre} hace un sonido`);
  }
}

class Perro extends Animal {
  hacerSonido(): void {
    console.log(`${this.nombre} ladra`);
  }
}

const miPerro = new Perro("Firulais");
miPerro.hacerSonido();

5. Compilación y Transpilación

TypeScript no se ejecuta directamente en el navegador o Node.js.
Debe compilarse a JavaScript mediante el comando:

tsc archivo.ts

Esto genera un archivo .js listo para ejecutarse.

Archivos importantes:

6. Módulos y Namespaces

Para organizar el código en archivos separados y reutilizables:

// archivo saludo.ts
export function saludar(nombre: string): string {
  return `Hola, ${nombre}`;
}

// archivo app.ts
import { saludar } from "./saludo";

console.log(saludar("Fernando"));

🔼 temas


Herramientas recomendadas

Estas herramientas te ayudarán a trabajar de manera más eficiente y profesional con TypeScript.

1. Node.js + NPM

Permite ejecutar y gestionar proyectos de TypeScript.

2. TypeScript Compiler (tsc)

El compilador oficial de TypeScript.

npm install -g typescript   # Instalación global
tsc -v                      # Verificar versión
tsc index.ts                # Compilar un archivo
tsc --init                  # Inicializar proyecto con `tsconfig.json`

3. Visual Studio Code (VSCode)

El editor más popular para trabajar con TypeScript.

Extensiones recomendadas:

4. ts-node

Permite ejecutar archivos TypeScript directamente sin compilar manualmente.

npm install -g ts-node    # Instalación
ts-node app.ts            # Uso

5. ESLint + Prettier

Mantienen el código limpio y legible.

Instalación rápida:

npm install eslint prettier -D

Configura un archivo .eslintrc.json y .prettierrc.

6. Git + GitHub

Para control de versiones y colaboración.

Comandos básicos:

git init
git add .
git commit -m "Primer commit"
git push origin main

7. Frameworks y Librerías compatibles

🔼 temas


Snippets rápidos

Fragmentos de código que se usan frecuentemente al trabajar con TypeScript.
Ideales para copiar y pegar en proyectos.

1. Declaración de variables con tipos

let nombre: string = "Fernando";
let edad: number = 30;
let activo: boolean = true;

2. Función con tipado en parámetros y retorno

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

3. Interface básica para un objeto

interface Usuario {
  id: number;
  nombre: string;
  activo: boolean;
}

const user: Usuario = {
  id: 1,
  nombre: "Fernando",
  activo: true,
};

4. Clase con constructor y método

class Persona {
  constructor(public nombre: string, public edad: number) {}

  saludar(): void {
    console.log(`Hola, soy ${this.nombre}`);
  }
}

const persona = new Persona("Carlos", 28);
persona.saludar();

5. Uso de enum

enum EstadoPedido {
  Pendiente,
  EnProceso,
  Entregado,
}

let estado: EstadoPedido = EstadoPedido.Pendiente;

6. Tipos genéricos

function identidad<T>(valor: T): T {
  return valor;
}

console.log(identidad<string>("Hola"));
console.log(identidad<number>(123));

7. Promesa tipada

function obtenerDatos(): Promise<string> {
  return new Promise((resolve) => {
    setTimeout(() => resolve("Datos recibidos"), 1000);
  });
}

8. Import y export

// archivo operaciones.ts
export function sumar(a: number, b: number): number {
  return a + b;
}

// archivo app.ts
import { sumar } from "./operaciones";
console.log(sumar(5, 3));

🔼 temas


Comandos

Resumen de los comandos y sintaxis principales con ejemplos breves.

1. Inicializar proyecto TypeScript

Crea un archivo de configuración tsconfig.json:

tsc --init

2. Compilar un archivo TypeScript

Convierte .ts a .js:

tsc archivo.ts

3. Ejecutar código sin compilar (ts-node)

ts-node app.ts

4. Tipos básicos

let texto: string = "Hola";
let numero: number = 100;
let esActivo: boolean = false;

5. Tipo any (evitar en lo posible)

let variable: any = "Puede ser cualquier cosa";
variable = 42;

6. Union Types

Permite más de un tipo en una variable.

let id: string | number;
id = "abc";
id = 123;

7. Tipado en funciones

function multiplicar(a: number, b: number): number {
  return a * b;
}

8. Parámetros opcionales

function saludar(nombre?: string) {
  console.log(`Hola ${nombre || "desconocido"}`);
}

9. Interfaces

interface Producto {
  id: number;
  nombre: string;
  precio: number;
}

const item: Producto = { id: 1, nombre: "Laptop", precio: 1500 };

10. Uso de readonly y optional (?)

interface Config {
  readonly version: string;
  descripcion?: string;
}

const conf: Config = { version: "1.0.0" };
// conf.version = "2.0.0"; ❌ Error

11. Genéricos

function identidad<T>(valor: T): T {
  return valor;
}

12. Modificadores de clase

class Vehiculo {
  public marca: string;
  private motor: string;
  protected modelo: string;

  constructor(marca: string, motor: string, modelo: string) {
    this.marca = marca;
    this.motor = motor;
    this.modelo = modelo;
  }
}

13. Compilar y vigilar cambios en tiempo real

tsc --watch

14. Instalar dependencias en proyecto

npm install typescript -D
npm install ts-node -D

15. Ejecutar proyecto con nodemon y ts-node

npx nodemon --exec ts-node src/index.ts

🔼 temas


Conceptos Claves

🟢 Básico

1. ¿Qué es TypeScript y en qué se diferencia de JavaScript?

TypeScript es un superset de JavaScript desarrollado por Microsoft que agrega tipado estático y características avanzadas al lenguaje.
La diferencia principal es que TypeScript permite detectar errores en tiempo de desarrollo y debe compilarse a JavaScript antes de ejecutarse.

Resumen:

2. Tipos primitivos en TypeScript

variable tipo valor
let nombre: string = "Fernando";
let edad: number = 30;
let activo: boolean = true;
let valor: null = null;
let indefinido: undefined = undefined;
let numeroGrande: bigint = 9007199254740991n;
let id: symbol = Symbol("id");
let nombre: string = "Fernando";                 # string
let edad: number = 30;                           # number
let activo: boolean = true;                      # boolean
let valor: null = null;                          # null
let indefinido: undefined = undefined;           # undefined
let numeroGrande: bigint = 9007199254740991n;    # bigint
let id: symbol = Symbol("id");                   # symbol

3. Interfaces vs Type Aliases

Ejemplo:

interface Usuario {
  id: number;
  nombre: string;
}

type Resultado = "success" | "error";

4. Union Types vs Intersection Types

let id: number | string;
id = 10;
id = "ABC123";
interface Persona {
  nombre: string;
}
interface Empleado {
  salario: number;
}

type PersonaEmpleado = Persona & Empleado;
const trabajador: PersonaEmpleado = { nombre: "Ana", salario: 5000 };

5. Tipar función con objeto como parámetro y valor de retorno

function calcularTotal(producto: { precio: number; cantidad: number }): number {
  return producto.precio * producto.cantidad;
}

const total = calcularTotal({ precio: 10, cantidad: 2 }); // 20

🟡 Intermedio

6. Generics y ejemplo práctico

Los Generics permiten escribir código reutilizable y flexible, indicando el tipo como parámetro.

function encontrarElemento<T>(
  arr: T[],
  predicado: (item: T) => boolean
): T | undefined {
  return arr.find(predicado);
}

const numeros = [1, 2, 3, 4];
const resultado = encontrarElemento(numeros, (num) => num > 2); // 3

7. Utility Types y ejemplo real

Utility Types son tipos predefinidos que ayudan a manipular otros tipos.

Ejemplo con Partial:
Hace que todas las propiedades de un tipo sean opcionales.

interface Usuario {
  id: number;
  nombre: string;
  email: string;
}

function actualizarUsuario(id: number, cambios: Partial<Usuario>) {
  // Solo se pasan los campos que se quieren actualizar
}

actualizarUsuario(1, { nombre: "Carlos" });

8. Significado de noImplicitAny

Habilitar noImplicitAny en tsconfig.json obliga a definir explícitamente los tipos.
Esto evita que TypeScript asigne automáticamente any cuando no se especifica el tipo.

// ❌ Sin noImplicitAny, esto sería válido:
function sumar(a, b) {
  return a + b;
}

// ✅ Con noImplicitAny habilitado, se requiere tipado:
function sumar(a: number, b: number): number {
  return a + b;
}

9. Type Guards y ejemplo práctico

Type Guards permiten validar el tipo en tiempo de ejecución.

interface Perro {
  ladrar: () => void;
}
interface Gato {
  maullar: () => void;
}

function esPerro(animal: Perro | Gato): animal is Perro {
  return (animal as Perro).ladrar !== undefined;
}

function hacerSonido(animal: Perro | Gato) {
  if (esPerro(animal)) {
    animal.ladrar();
  } else {
    animal.maullar();
  }
}

10. Tuples vs Arreglos

Ejemplo:

let coordenadas: [number, number] = [10, 20];
// coordenadas[0] = "hola"; ❌ Error

let lista: number[] = [1, 2, 3];
lista.push(4); // ✅ Válido

Se usan en casos como representar pares clave-valor o datos estructurados.


🔴 Avanzado

11. Decorators y tipos

Los Decorators añaden metadatos o modifican el comportamiento de clases y elementos.

function Log(clase: Function) {
  console.log(`Clase creada: ${clase.name}`);
}

@Log
class Persona {}
function MedirTiempo(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  const metodoOriginal = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.time("Tiempo");
    const resultado = metodoOriginal.apply(this, args);
    console.timeEnd("Tiempo");
    return resultado;
  };
}

class Calculadora {
  @MedirTiempo
  sumar(a: number, b: number) {
    return a + b;
  }
}

12. Conditional Types

Permiten definir tipos según una condición.

type EsString<T> = T extends string ? "Es texto" : "No es texto";

type Caso1 = EsString<string>; // "Es texto"
type Caso2 = EsString<number>; // "No es texto"

Esto ayuda a crear tipos dinámicos y reutilizables.

13. Uso del tipo never

El tipo never se utiliza en funciones que nunca retornan un valor, como errores o loops infinitos.

function lanzarError(mensaje: string): never {
  throw new Error(mensaje);
}

Se usa para indicar que la función no tiene un punto de retorno.

14. Migración de JavaScript a TypeScript

Estrategia:

  1. Configurar tsconfig.json con "allowJs": true y "checkJs": false.
  2. Renombrar archivos .js a .ts de forma progresiva.
  3. Activar "strict": true gradualmente.
  4. Usar Partial, any temporalmente en lugares complejos.
  5. Agregar pruebas automáticas antes y después de la migración.

Configuraciones clave:

15. Manejo seguro de múltiples esquemas en una API

Usar discriminated unions para garantizar que todos los casos sean manejados.

type RespuestaAPI =
  | { type: "usuario"; data: { id: number; nombre: string } }
  | { type: "producto"; data: { id: number; precio: number } };

function procesarRespuesta(respuesta: RespuestaAPI) {
  switch (respuesta.type) {
    case "usuario":
      console.log(respuesta.data.nombre);
      break;
    case "producto":
      console.log(respuesta.data.precio);
      break;
    default:
      const exhaustivo: never = respuesta;
      return exhaustivo;
  }
}

Esto asegura que TypeScript te obligue a cubrir todos los casos.

🔼 temas