🚀 ¡Transforma tu idea en un proyecto exitoso!
Desarrollo moderno, creativo, eficiente y escalable.
Comunicación clara, entregas puntuales y soluciones que realmente funcionan.

¡Conversemos!

Preguntas y Respuestas de TypeScript: De Principiante a Experto

¡Domina TypeScript como un pro! Esta guía te lleva de lo básico a lo avanzado con ejemplos claros, respuestas detalladas y explicaciones paso a paso.
No solo memorizarás, entenderás cómo funciona TypeScript para brillar en exámenes y entrevistas técnicas.

1¿Qué es TypeScript y cuál es su principal ventaja sobre JavaScript?

TypeScript es un superconjunto de JavaScript que añade tipado estático opcional. Su principal ventaja es que permite detectar errores de tipo en tiempo de compilación, lo que mejora la robustez y el mantenimiento del código en proyectos grandes.

Ejemplo 1 (JavaScript sin tipado):
typescript
function sumar(a, b) {
  return a + b;
}
console.log(sumar(5, "10")); 
// Salida: "510" (No hay error, pero el resultado es inesperado)
  Explicación

En JavaScript, el motor de ejecución convierte el number 5 y el string “10”, concatenándolos en lugar de sumarlos, lo que genera un resultado no deseado sin lanzar un error.

Ejemplo 2 (TypeScript con tipado):
typescript
function sumar(a: number, b: number): number {
  return a + b;
}
sumar(5, "10"); // Error de compilación: Argumento de tipo 'string' no es asignable a parámetro de tipo 'number'.
  Explicación

TypeScript detecta la incompatibilidad de tipos antes de la ejecución, previniendo el error y asegurando la lógica de la función.

2¿Qué es un 'tipo' en TypeScript y cómo se declaran las variables con tipos?

Un tipo define el conjunto de valores que una variable puede tener. Se declaran usando la sintaxis let variable: Tipo = valor;.

Ejemplo 1 (variable con tipo string):
typescript
let nombre: string = "Juan";
  Explicación

Aquí se declara que la variable nombre solo puede almacenar valores de tipo cadena de texto (string).

Ejemplo 2 (variable con tipo boolean):
typescript
let esActivo: boolean = true;
  Explicación

Esta variable esActivo está tipada para aceptar únicamente valores booleanos (true o false).

3Explica la diferencia entre any y unknown. ¿Cuándo usarías cada uno?

any desactiva la comprobación de tipos por completo, permitiendo cualquier operación. unknown es un tipo seguro que obliga a realizar una comprobación de tipo (type narrowing) antes de poder operar con la variable. Se prefiere unknown por seguridad.

Ejemplo 1 (any):
typescript
let valorAny: any = "hola";
valorAny.toUpperCase(); // Válido. No hay comprobación de tipo.
valorAny = 10;
valorAny.toFixed(2); // Válido.
  Explicación

El tipo any permite realizar cualquier acción sobre la variable sin que el compilador se queje, lo que puede llevar a errores en tiempo de ejecución.

Ejemplo 2 (unknown):
typescript
let valorUnknown: unknown = "hola";
// valorUnknown.toUpperCase(); // Error: 'valorUnknown' es de tipo 'unknown'.
if (typeof valorUnknown === 'string') {
valorUnknown.toUpperCase(); // Válido tras la comprobación.
}
  Explicación

Con unknown, el compilador fuerza una verificación explícita (typeof) antes de permitir el uso de métodos específicos del tipo.

4¿Qué es una interfaz (interface) en TypeScript y para qué se utiliza?

Una interfaz define la estructura de un objeto, especificando las propiedades y sus tipos. Se utiliza para asegurar que los objetos cumplan con una determinada forma, lo que es útil para la validación y la colaboración en equipo.

Ejemplo 1 (Definición de interfaz):
typescript
interface Coche {
marca: string;
modelo: string;
anio: number;
}
  Explicación

Se define una plantilla para los objetos de tipo Coche, especificando que deben tener las propiedades marca (string), modelo (string) y anio (number).

Ejemplo 2 (Uso de la interfaz):
typescript
const miCoche: Coche = {
marca: "Toyota",
modelo: "Corolla",
anio: 2020,
};
// const cocheInvalido: Coche = { marca: "Ford" }; // Error: faltan propiedades 'modelo' y 'anio'.
  Explicación

Al intentar crear un objeto que no cumple con la estructura de la interfaz, el compilador muestra un error, garantizando la consistencia del código.

5¿Cuál es la diferencia entre un type y una interface?

Las interfaces solo se usan para describir la forma de los objetos y se pueden fusionar (declaración de interfaces con el mismo nombre). Los types son más flexibles, pueden definir tipos primitivos, uniones, intersecciones, y no se pueden fusionar.

Ejemplo 1 (Uso de type para una unión de tipos):
typescript
type Id = string | number;
let userId: Id = 123;
let productId: Id = "abc-456";
  Explicación

Un type alias permite crear un nuevo nombre para un tipo existente, como una unión de tipos, lo cual no es posible con una interface.

Ejemplo 2 (Demostración de fusión con interface):
typescript
interface Persona {
nombre: string;
}
interface Persona {
edad: number;
}
// La interfaz final 'Persona' tiene 'nombre' y 'edad'.
let p: Persona = { nombre: "Ana", edad: 30 };
  Explicación

Las declaraciones de interface con el mismo nombre se combinan automáticamente, un comportamiento útil para modular el código.

6¿Qué es la 'inferencia de tipos' (Type Inference) en TypeScript?

Es la capacidad del compilador de TypeScript para deducir automáticamente el tipo de una variable basándose en su valor inicial, sin que sea necesario declararlo explícitamente.

Ejemplo 1 (Inferencia de string):
typescript
let nombre = "Juan"; // TypeScript infiere que 'nombre' es de tipo 'string'.
// nombre = 123; // Error: Tipo 'number' no es asignable a tipo 'string'.
  Explicación

El compilador ve que la variable se inicializa con una cadena de texto y automáticamente le asigna el tipo string.

Ejemplo 2 (Inferencia en una función):
typescript
function multiplicar(a: number, b: number) {
return a * b; // TypeScript infiere que el tipo de retorno es 'number'.
}
  Explicación

El tipo de retorno de la función se infiere a partir de la operación (a * b), que resulta en un number.

7¿Cómo se define una función que recibe un argumento y devuelve un valor de un tipo específico?

Se usa la sintaxis: function nombre(parametro: TipoParametro): TipoRetorno { ... }

Ejemplo 1 (Función que devuelve un string):
typescript
function saludar(nombre: string): string {
return `Hola, ${nombre}!`;
}
  Explicación

Se especifica que el parámetro nombre debe ser un string y la función debe retornar un valor del mismo tipo.

Ejemplo 2 (Función que devuelve un number):
typescript
function duplicar(num: number): number {
return num * 2;
}
  Explicación

Esta función acepta un número como entrada y garantiza que el valor de retorno también sea un número.

8Explica el concepto de 'unión de tipos' (Union Types).

Permite que una variable pueda tener uno de varios tipos posibles. Se define con el operador |, por ejemplo: let id: string | number;.

Ejemplo 1 (Variable que puede ser string o number):
typescript
let id: string | number;
id = 101; // Válido
id = "abc-123"; // Válido
// id = true; // Error: Tipo 'boolean' no es asignable a tipo 'string | number'.
  Explicación

La variable id puede almacenar tanto un número como una cadena de texto, pero no otro tipo de dato.

Ejemplo 2 (Parámetro de función con unión de tipos):
typescript
function imprimirId(id: string | number) {
console.log(`El ID es: ${id}`);
}
imprimirId(5);
imprimirId("xyz");
  Explicación

La función imprimirId está diseñada para trabajar con datos que pueden ser de dos tipos diferentes, lo que la hace más flexible.

9¿Qué es una 'tupla' (Tuple) y cómo se diferencia de un array normal?

Una tupla es un array con un número fijo y predefinido de elementos, donde cada elemento puede tener un tipo diferente. A diferencia de los arrays, la tupla mantiene un orden y una longitud estricta. Ejemplo: [string, number].

Ejemplo 1 (Tupla que define un par clave-valor):
typescript
let par: [string, number] = ["edad", 25];
// par = [25, "edad"]; // Error: Tipos en orden incorrecto.
  Explicación

La tupla asegura que el primer elemento sea un string y el segundo un number, y no permite reordenarlos.

Ejemplo 2 (Tupla para coordenadas):
typescript
let coordenadas: [number, number] = [40.7128, -74.0060];
// coordenadas.push("Error"); // Error: No se puede agregar un string a la tupla.
  Explicación

La tupla garantiza no solo los tipos, sino también la cantidad de elementos, lo que la hace ideal para datos estructurados como coordenadas.

10¿Cómo se pueden hacer opcionales las propiedades de un objeto en una interfaz?

Se usa el operador ? después del nombre de la propiedad. Esto indica que la propiedad puede estar presente o no en el objeto.

Ejemplo 1 (Interfaz con propiedades opcionales):
typescript
interface Usuario {
nombre: string;
edad?: number; // Propiedad opcional
email?: string; // Propiedad opcional
}
  Explicación

Las propiedades edad y email son opcionales, por lo que un objeto Usuario puede existir sin ellas.

Ejemplo 2 (Uso de la interfaz con propiedades opcionales):
typescript
const usuario1: Usuario = { nombre: "Ana" }; // Válido
const usuario2: Usuario = { nombre: "Luis", edad: 30 }; // Válido
const usuario3: Usuario = { nombre: "María", edad: 25, email: "maria@example.com" }; // Válido
  Explicación

Todos los objetos son válidos porque solo nombre es obligatorio, mientras que edad y email son opcionales.

11¿Qué es el tipo any y cuándo debería evitarse?

El tipo any desactiva completamente el sistema de tipos de TypeScript, permitiendo cualquier valor. Debe evitarse porque elimina las ventajas de TypeScript como la detección de errores y el autocompletado.

Ejemplo 1 (Uso problemático de any):
typescript
let dato: any = "Hola";
dato = 42;
dato = true;
dato.metodoInexistente(); // No hay error en tiempo de compilación
  Explicación

Con any, TypeScript no puede detectar errores como llamar a métodos inexistentes, perdiendo la seguridad de tipos.

Ejemplo 2 (Alternativa mejor usando unknown):
typescript
let dato: unknown = "Hola";
if (typeof dato === "string") {
console.log(dato.toUpperCase()); // Seguro después de la verificación
}
  Explicación

unknown es más seguro que any porque requiere verificaciones de tipo antes de usar el valor.

12Explica la diferencia entre interface y type en TypeScript.

Ambos definen formas de objetos, pero interface es extensible (se puede ampliar) y type es más flexible (puede definir uniones, primitivos, etc.). interface es mejor para objetos que pueden crecer.

Ejemplo 1 (Extensibilidad de interface):
typescript
interface Animal {
nombre: string;
}
interface Animal { // Se puede extender
edad: number;
}
const perro: Animal = { nombre: "Rex", edad: 3 }; // Ambas propiedades requeridas
  Explicación

Las interfaces se pueden extender declarándolas múltiples veces, combinando automáticamente sus propiedades.

Ejemplo 2 (Flexibilidad de type):
typescript
type ID = string | number; // Unión de tipos
type Usuario = {
id: ID;
nombre: string;
};
// type Usuario = { email: string }; // Error: No se puede redeclarar
  Explicación

type puede definir uniones, primitivos y alias complejos, pero no se puede extender como interface.

Es el archivo de configuración para el compilador de TypeScript (tsc). Contiene opciones como el destino de compilación (ES5, ES6), la ruta de los archivos de entrada, y si se deben habilitar ciertas comprobaciones de tipo.

  • Ejemplo 1 (Configuración de target y outDir):
json
{
"compilerOptions": {
  "target": "es5",
  "outDir": "./dist"
}
}
  Explicación

Esta configuración le indica al compilador que genere código JavaScript compatible con la versión ES5 y lo guarde en una carpeta específica.

Ejemplo 2 (Configuración de strict):
json
{
  "compilerOptions": {
  "strict": true
  }
}
  Explicación

La opción strict activa un conjunto de reglas de tipado más rigurosas para un código más seguro y robusto.

13¿Qué es el 'type assertion' (as keyword)? ¿Cuándo se usa?

Es una forma de “indicarle” al compilador que sabes más sobre el tipo de una variable de lo que él puede inferir. Se utiliza para anular la inferencia de tipos por defecto, pero debe usarse con cuidado.

Ejemplo 1 (Asignación de un elemento de DOM):
typescript
const miCanvas = document.getElementById("main-canvas") as HTMLCanvasElement;
  Explicación

getElementById puede devolver HTMLElement o null. Con as HTMLCanvasElement, le aseguramos al compilador que el elemento es del tipo que necesitamos.

Ejemplo 2 (Conversión de tipo en un any):
typescript
let algo: any = "esto es un string";
let longitud: number = (algo as string).length; // Indicamos al compilador que 'algo' es un string.
  Explicación

Se utiliza para tratar una variable de tipo any como un tipo específico para poder acceder a sus propiedades y métodos.

14¿Qué es la 'protección de tipos' (Type Guards)?

Son técnicas para verificar el tipo de una variable en tiempo de ejecución, permitiendo que TypeScript infiera automáticamente el tipo correcto dentro de un bloque de código específico.

Ejemplo 1 (Type guard con typeof):
typescript
function procesar(valor: string | number) {
if (typeof valor === "string") {
  console.log(valor.toUpperCase()); // TypeScript sabe que es string
} else {
  console.log(valor.toFixed(2)); // TypeScript sabe que es number
}
}
  Explicación

El typeof actúa como type guard, permitiendo que TypeScript infiera automáticamente el tipo correcto en cada rama del if.

Ejemplo 2 (Type guard personalizado):
typescript
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(); // TypeScript sabe que es Perro
} else {
  animal.maullar(); // TypeScript sabe que es Gato
}
}
  Explicación

La función esPerro es un type guard personalizado que usa la sintaxis animal is Perro para indicar a TypeScript el tipo específico.

Ejemplo 1 (Uso de typeof):

Son expresiones que verifican si una variable es de un tipo determinado en un bloque de código. Por ejemplo, typeof y instanceof son guardianes de tipo integrados.

typescript
function imprimirLongitud(texto: string | string[]) {
if (typeof texto === "string") {
  console.log(texto.length); // Aquí 'texto' es un string.
} else {
  console.log(texto.join(" ").length); // Aquí 'texto' es un string[].
}
}
  Explicación

La condición typeof texto === "string" funciona como un “guardián”, lo que permite al compilador saber el tipo de texto dentro de ese bloque de código.

Ejemplo 2 (Uso de instanceof):
typescript
class Perro {}
class Gato {}
function esAnimal(animal: Perro | Gato) {
if (animal instanceof Perro) {
  console.log("Es un perro.");
} else {
  console.log("Es un gato.");
}
}
  Explicación

Se utiliza instanceof para verificar si un objeto es una instancia de una clase específica, lo que ayuda a refinar su tipo.

Ejemplo 2 (Uso de instanceof):
typescript
class Perro {}
class Gato {}
function esAnimal(animal: Perro | Gato) {
if (animal instanceof Perro) {
  console.log("Es un perro.");
} else {
  console.log("Es un gato.");
}
}
  Explicación

Se utiliza instanceof para verificar si un objeto es una instancia de una clase específica, lo que ayuda a refinar su tipo.

15¿Qué son las 'propiedades de solo lectura' (Readonly properties) y cómo se definen?

Son propiedades de un objeto que solo se pueden asignar en el momento de la inicialización y no pueden ser modificadas posteriormente. Se definen con la palabra clave readonly.

Ejemplo 1 (Propiedad readonly en una interfaz):
typescript
interface Punto {
readonly x: number;
readonly y: number;
}
let p1: Punto = { x: 10, y: 20 };
// p1.x = 5; // Error: No se puede asignar a 'x' porque es una propiedad de solo lectura.
  Explicación

Una vez que se inicializa el objeto, las propiedades marcadas como readonly no se pueden reasignar, garantizando la inmutabilidad.

Ejemplo 2 (Propiedad readonly en una clase):
typescript
class Usuario {
readonly id: string;
constructor(id: string) {
  this.id = id;
}
}
const usuario = new Usuario("user-123");
// usuario.id = "user-456"; // Error: No se puede modificar la propiedad 'id'.
  Explicación

Esto protege la propiedad id de ser cambiada accidentalmente después de que la instancia ha sido creada.

Nuevas Preguntas Adicionales

16¿Qué es la 'desestructuración' con tipado?

Es la capacidad de extraer valores de objetos o arrays y asignarlos a variables con tipado específico, combinando la sintaxis de desestructuración de JavaScript con las características de tipado de TypeScript.

Ejemplo 1 (Desestructuración de objeto):
typescript
interface Persona {
nombre: string;
edad: number;
}
const persona: Persona = { nombre: "Juan", edad: 30 };
const { nombre, edad } = persona; // TypeScript infiere los tipos de 'nombre' y 'edad'.
  Explicación

Los tipos de las variables nombre y edad se infieren automáticamente de la interfaz Persona.

Ejemplo 2 (Desestructuración de array):
typescript
let numeros: [number, number] = [1, 2];
let [x, y] = numeros; // x: number, y: number.
  Explicación

En este caso, TypeScript sabe que x y y son números basados en la tupla numeros.

17¿Qué son los tipos genéricos (Generics) en TypeScript?

Los genéricos permiten escribir componentes que funcionan con múltiples tipos de datos, en lugar de uno solo. Esto proporciona flexibilidad y reutilización sin perder los beneficios de la verificación de tipos.

Ejemplo 1 (Función genérica para un array):
typescript
function obtenerPrimerElemento<T>(arr: T[]): T {
return arr[0];
}
const primerNumero = obtenerPrimerElemento([1, 2, 3]); // Tipo 'number'.
const primeraLetra = obtenerPrimerElemento(["a", "b", "c"]); // Tipo 'string'.
  Explicación

La función obtenerPrimerElemento puede trabajar con arrays de cualquier tipo, y el tipo de retorno se infiere a partir del tipo del array pasado como argumento.

Ejemplo 2 (Interfaz genérica):
typescript
interface Caja<T> {
contenido: T;
}
const cajaNumero: Caja<number> = { contenido: 100 };
const cajaTexto: Caja<string> = { contenido: "Hola" };
  Explicación

La interfaz Caja se puede reutilizar para crear contenedores de cualquier tipo de dato, manteniendo la seguridad de tipos.

18Explica qué es un 'módulo' en TypeScript y cómo se importan/exportan. ¿Cuál es la diferencia con los 'namespaces'?

Los módulos son una forma de organizar el código en archivos separados para encapsular funcionalidades. Se utilizan las palabras clave export e import. Los namespaces son una característica más antigua para organizar código globalmente y se consideran obsoletos.

Ejemplo 1 (Exportación e importación):
typescript
// archivo 'util.ts'
export function sumar(a: number, b: number): number {
return a + b;
}

// archivo 'main.ts'
import { sumar } from "./util";
console.log(sumar(2, 3));
  Explicación

La función sumar se exporta desde un archivo para ser utilizada en otro archivo a través de la instrucción import.

Ejemplo 2 (Comparación con namespace):
typescript
namespace Matematicas {
export function sumar(a: number, b: number) {
  return a + b;
}
}
// Matematicas.sumar(2, 3);
  Explicación

Un namespace agrupa el código para evitar colisiones de nombres globales, pero el enfoque modular con import/export es el estándar moderno.

19¿Qué es la 'decoración' (Decorators) en TypeScript?

Los decoradores son una característica experimental que permite añadir metadatos o modificar clases, propiedades, métodos o parámetros en tiempo de diseño. Se utilizan con el símbolo @.

Ejemplo 1 (Decorador de clase):
typescript
function HolaMundo(target: Function) {
console.log("Hola desde el decorador!");
}
@HolaMundo
class MiClase {}
  Explicación

El decorador @HolaMundo se ejecuta cuando se declara la clase MiClase, lo que puede ser útil para la inyección de dependencias o la instrumentación de código.

Ejemplo 2 (Decorador de método):
typescript
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
  console.log(`Llamando al método ${key} con argumentos:`, args);
  return originalMethod.apply(this, args);
};
return descriptor;
}
class Servicio {
@log
imprimir(mensaje: string) {
  console.log(mensaje);
}
}
new Servicio().imprimir("Hola!");
  Explicación

El decorador @log modifica el método imprimir para que imprima un mensaje antes de su ejecución original, lo que es útil para el registro (logging) o la validación.

20Explica la diferencia entre null y undefined en TypeScript y cómo se relacionan con la opción de compilador strictNullChecks.

undefined significa que una variable ha sido declarada pero no se le ha asignado un valor. null es un valor asignado intencionalmente para representar la ausencia de un objeto. La opción strictNullChecks fuerza una verificación más estricta.

Ejemplo 1 (strictNullChecks: false):
typescript
// Con "strictNullChecks": false
let miString: string = "hola";
miString = null; // Válido.
  Explicación

Sin la opción strictNullChecks, null y undefined pueden ser asignados a cualquier tipo de variable, lo que puede provocar errores de null-pointer en tiempo de ejecución.

Ejemplo 2 (strictNullChecks: true):
typescript
// Con "strictNullChecks": true
let miString: string = "hola";
// miString = null; // Error: El tipo 'null' no es asignable al tipo 'string'.
let miStringOpcional: string | null = "hola"; // Válido, se usa una unión de tipos.
miStringOpcional = null;
  Explicación

Con strictNullChecks activado, el compilador exige que se use una unión de tipos (string | null) para poder asignar null a una variable, lo que promueve un código más seguro.