🚨 ¡Nueva review! ¡Mi teclado ideal! ⌨️ Perfecto para programar, el Logitech MX Keys S . ¡Échale un ojo! 👀

Tipos básicos e Inferencia en TypeScript: Deja que el código trabaje por ti

Aprende los fundamentos del tipado y descubre la magia de la inferencia

Escrito por domin el 14 de marzo de 2026

Bienvenido al segundo post de la serie TypeScript, si te perdiste el primero, empieza por aquí que te va a hacer falta.

Hoy vamos a meternos en lo que hace que TypeScript sea tan potente: los tipos básicos y, sobre todo, la inferencia de tipos. Cuando acabes este post vas a entender por qué la mitad de las veces ni siquiera necesitas escribir los tipos a mano, TypeScript los adivina solito.

Logo de TypeScript sobre fondo azul con código.

1. Tipado fuerte y estático: las dos reglas de oro

Antes de ver los tipos, necesitas entender dos conceptos que son la base de todo en TypeScript:

🔒 Tipado estático

Los tipos se verifican en tiempo de compilación, antes de ejecutar nada. Si hay un error de tipos, el código ni compila. Es como un portero de discoteca que no te deja entrar por ir con la camiseta de tu equipo de fútbol favorito.

💪 Tipado fuerte

Si una variable nace siendo un string, no puede mutar a number después. No hay conversiones automáticas raras. Cada tipo se respeta.

¿Qué significa esto en la práctica? Que en TypeScript no puedes hacer estas cositas:

let nombre = 'Domin'; // TypeScript sabe que es string
nombre = 42;          // ❌ Error: Type 'number' is not assignable to type 'string'

let edad = 30;        // TypeScript sabe que es number
edad = 'treinta';     // ❌ Error: Type 'string' is not assignable to type 'number'

Mientras que en JavaScript, esto se puede hacer porque tu lo vales y porquesi. En TypeScript, el editor te marca el error al momento de escribirlo, como debe ser.

Dato clave: TypeScript es y . JavaScript, en cambio, es débil y dinámico, de ahí el caos.


2. Los tipos básicos: el abecedario de TypeScript

TypeScript tiene unos pocos de tipos primitivos que son la base de todo, los vas a usar frecuentemente:

string — Texto

let nombre: string = 'Domin';
let saludo: string = `Hola, ${nombre}`; // Template literals también
let vacio: string = '';                 // String vacío, sigue siendo string

number — Números (todos)

let edad: number = 28;
let precio: number = 19.99;    // Decimales incluidos
let negativo: number = -5;
let hex: number = 0xff;        // Hexadecimal
let infinito: number = Infinity;

A diferencia de otros lenguajes, TypeScript no distingue entre enteros y decimales, todo es number. Nada de int, float, double… aquí todo es tipo number e ya.

boolean — Verdadero o falso

let activo: boolean = true;
let eliminado: boolean = false;
// ❌ Esto NO es un boolean:
let noEsBoolean: boolean = 'true'; // Error: Type 'string' is not assignable

null y undefined — Los fantasmas

let nada: null = null;
let sinDefinir: undefined = undefined;

Estos dos son especiales. En TypeScript con activado (que es lo recomendado), null y undefined son tipos independientes. No puedes meterlos donde no toca:

let nombre: string = null;      // ❌ Error con strictNullChecks
let edad: number = undefined;   // ❌ Error con strictNullChecks

// ✅ Si quieres permitirlo, úsalo explícitamente:
let nombreOpcional: string | null = null;         // Ahora sí
let edadOpcional: number | undefined = undefined; // Ahora sí

Resumen visual de los tipos básicos

TipoDescripciónEjemplo
stringCadenas de texto"hola", 'mundo', `template`
numberNúmeros (enteros y decimales)42, 3.14, -7, 0xff
booleanVerdadero o falsotrue, false
nullAusencia intencional de valornull
undefinedVariable declarada sin valorundefined

3. La magia de la Inferencia de tipos

Hasta ahora hemos escrito los tipos a mano: let nombre: string = "Domin". Pero, ¿y si te digo que la mayoría de las veces no hace falta?

TypeScript tiene un sistema de tan potente que deduce los tipos por ti mirando qué valor asignas.

// ❌ Esto funciona, pero es REDUNDANTE:
let nombre: string = 'Domin';
let edad: number = 28;
let activo: boolean = true;

// ✅ TypeScript ya lo sabe sin que se lo digas:
let nombre = 'Domin';   // Tipo inferido: string
let edad = 28;           // Tipo inferido: number
let activo = true;       // Tipo inferido: boolean

TypeScript mira el valor 'Domin' y piensa: “Esto es un string, así que nombre es un string. No necesitas decírmelo, nene”. Y lo mejor es que el autocompletado y la protección de tipos funcionan exactamente igual.

Pruébalo tú mismo

Inferencia en acción 0 / 4
~/ts-demo $
Pulsa para ejecutar el siguiente comando

¿Lo ves? En ningún momento hemos escrito : string y sin embargo TypeScript sabe que mensaje es un string. Si intentas asignarle un número, te frena en seco. Y .toUpperCase() aparece en el autocompletado porque sabe que es un string. Atención que eso es la inferencia que mencionamos en el título!

La inferencia también funciona con funciones

TypeScript no solo infiere variables, también infiere lo que devuelve una función:

// TypeScript infiere que el retorno es number
function sumar(a: number, b: number) {
    return a + b;
}

const resultado = sumar(5, 3); // tipo inferido: number
resultado.toFixed(2);          // ✅ Autocompletado de number

// TypeScript infiere que el retorno es string
function saludar(nombre: string) {
    return `Hola, ${nombre}!`;
}

const saludo = saludar('Domin'); // tipo inferido: string
saludo.toUpperCase();            // ✅ Autocompletado de string

Fíjate que no hemos puesto : number ni : string en el retorno de las funciones y TypeScript lo deduce solo mirando qué hay dentro del return. Esto es la inferencia.

¿Cuándo escribir el tipo y cuándo dejar que infiera?

Esto es lo que me hubiera gustado saber a mi desde el principio:

Escribe el tipo explícitamente cuando...
  • Declaras una variable sin asignarle valor: let nombre: string;
  • El tipo no es obvio al leer el código
  • Quieres documentar una función pública (parámetros)
  • Trabajas con tipos complejos (objetos, arrays de objetos)
  • El valor puede ser de varios tipos (string | number)
Deja que TypeScript infiera cuando...
  • Asignas un valor directamente: let x = 42
  • El retorno de la función es obvio por el código
  • Es una variable local con un valor simple
  • Estás haciendo una operación que el tipo es evidente

Si TypeScript puede inferirlo, no lo escribas. Si no puede, ayúdalo.


4. Inferencia en objetos y arrays

La inferencia no se queda en tipos simples, también funciona con estructuras más complejas:

Objetos

// TypeScript infiere toda la estructura del objeto
const usuario = {
    nombre: 'Domin',
    edad: 28,
    activo: true,
};
// Tipo inferido: { nombre: string; edad: number; activo: boolean }
usuario.nombre.toUpperCase(); // ✅ Sabe que es string
usuario.edad.toFixed(2);      // ✅ Sabe que es number
usuario.activo = 'sí';        // ❌ Error: Type 'string' is not assignable to type 'boolean'
usuario.email;                 // ❌ Error: Property 'email' does not exist

Arrays

// TypeScript infiere el tipo del array por sus elementos
const numeros = [1, 2, 3];         // Tipo: number[]
const nombres = ['Ana', 'Luis'];   // Tipo: string[]
const mixto = [1, 'dos', true];    // Tipo: (number | string | boolean)[]

numeros.push('cuatro'); // ❌ Error: Argument of type 'string'
                        //    is not assignable to parameter of type 'number'

nombres.map(n => n.toUpperCase()); // ✅ Sabe que cada 'n' es string

Ojito con el array mixto: TypeScript infiere un tipo unión (number | string | boolean)[]. Es listo, pero intenta evitar arrays con tipos mezclados… eso es JavaScript caótico, no TypeScript limpio.

El autocompletado se vuelve mágico

Cuando TypeScript infiere el tipo de un objeto, tu editor sabe exactamente qué propiedades tiene, mira este ejemplo:

const producto = {
    nombre: 'Teclado MX Keys',
    precio: 119.99,
    enStock: true,
    tags: ['periférico', 'logitech'],
};

// Al escribir "producto." tu editor te sugiere:
// → nombre (string)
// → precio (number)
// → enStock (boolean)
// → tags (string[])

// Y encadenas métodos con autocompletado completo:
producto.tags.filter(t => t.startsWith('log')); // ✅
producto.precio.toFixed(2);                      // ✅
producto.nombre.split(' ');                       // ✅

Esto sin haber escrito ni un solo tipo explícito, todo inferido. Si vienes de trabajar con JavaScript vanilla donde el autocompletado es un a ver si cuela, esto es canela fina nene!


5. El peligro del any: el villano de TypeScript

Ahora vienen las malas noticias, existe un tipo en TypeScript que lo destruye todo: .

let cosa: any = 'hola';
cosa = 42;           // ✅ Sin error
cosa = true;         // ✅ Sin error
cosa = { a: 1 };    // ✅ Sin error
cosa.metodoQueNoExiste(); // ✅ Sin error... PERO PETARÁ EN RUNTIME 💥

¿Ves el problema? Con any le estás diciendo a TypeScript: “Calla, tú no sabes nada. Yo me encargo.” Y TypeScript se calla y no te avisa de errores. No te da autocompletado. No te protege de nada. Estás de vuelta en JavaScript puro, pero con la falsa sensación de que estás “usando TypeScript”.

PROS

Puede servir como parche temporal mientras migras de JS a TS
Útil en prototipado rápido que vas a tirar después

CONTRAS

Destruye completamente la seguridad de tipos
Sin autocompletado ni sugerencias del editor
Los errores aparecen en runtime, no en compilación
Se propaga: si una función devuelve any, todo lo que la use pierde tipos
Crea una falsa sensación de seguridad

El efecto dominó del any

Lo peor del any no es usarlo una vez, es que se contagia:

function obtenerDatos(): any {
    return { nombre: 'Domin', edad: 28 };
}

const datos = obtenerDatos();  // tipo: any
const nombre = datos.nombre;   // tipo: any (¡se ha propagado!)
const largo = nombre.length;   // tipo: any (¡otra vez!)
// Todo el código que depende de esta función pierde tipos
// Es como un virus que infecta toda la cadena

Una sola función con any en el retorno contamina todo lo que la toque. El any es una bola de nieve que crece y crece hasta que tu proyecto TypeScript es básicamente JavaScript disfrazado. Por eso, si ves un código en TypeScript y aparece any, preocupate!

La alternativa segura: unknown

Si necesitas un tipo genérico pero sin perder la seguridad, existe :

let dato: unknown = 'hola';

// ❌ Con unknown NO puedes hacer esto directamente:
dato.toUpperCase(); // Error: 'dato' is of type 'unknown'

// ✅ Primero tienes que VERIFICAR el tipo:
if (typeof dato === 'string') {
    dato.toUpperCase(); // Ahora sí, TypeScript sabe que es string
}

if (typeof dato === 'number') {
    dato.toFixed(2); // Aquí sabe que es number
}

La diferencia es bastante considerable porque unknown te obliga a comprobar qué tipo es antes de usarlo. Es como decir: “No sé qué es esto, pero antes de tocarlo voy a asegurarme”. Mientras que any es: “Me da igual qué sea, me llamo Ralph”.

Característicaanyunknown
Asignar cualquier valor✅ Sí✅ Sí
Usar sin comprobar tipo✅ Sí (peligroso)❌ No (te obliga a verificar)
Autocompletado del editor❌ Ninguno✅ Tras la verificación
Seguridad de tipos❌ Nula✅ Completa
¿Cuándo usarlo?Casi nunca (migración JS→TS)Datos de origen desconocido (APIs, JSON)

6. any vs unknown en la práctica

Veamos un caso real, imaginando que recibes datos de una API y no sabes qué estructura tienen:

// ❌ MAL: con any
async function fetchUsuarioMal(): Promise<any> {
    const res = await fetch('/api/usuario');
    return res.json(); // Devuelve any... adiós tipos
}

const user = await fetchUsuarioMal();
// user.nombre → any (sin autocompletado, sin protección)
// user.loquesea → any (ni se queja)

// ✅ BIEN: con unknown + validación
async function fetchUsuarioBien(): Promise<unknown> {
    const res = await fetch('/api/usuario');
    return res.json();
}

const data = await fetchUsuarioBien();

// Antes de usar, verificamos:
if (
    typeof data === 'object' &&
    data !== null &&
    'nombre' in data &&
    'edad' in data
) {
    // Ahora TypeScript sabe que tiene nombre y edad
    console.log(data.nombre, data.edad);
}

¿Cuál es más código? La versión con unknown. ¿Cuál es más segura? También la de unknown. Y ya sabes lo que decimos: más código ahora, menos bugs después. Ta enterao o no.


7. Errores comunes de novato con los tipos

Estos son los errores que todo el mundo comete cuando empieza con TypeScript. Si los evitas desde el principio, ya vas por delante del 80% de la gente:

🔄 Tipar lo que ya se infiere

let x: number = 5; — Redundante. TypeScript ya sabe que 5 es number. Simplifica: let x = 5;

🚨 Usar any "porque funciona"

El clásico const data: any = ... para quitarse el error de encima. No. Busca el tipo correcto o usa unknown.

⚠️ Olvidar strictNullChecks

Sin strict mode, null y undefined se cuelan en todos los tipos sin avisar. Siempre "strict": true en tsconfig.

💡 No aprovechar el autocompletado

Si TypeScript infiere un tipo, úsalo. Escribe variable. y deja que el editor te sugiera. Es la mayor ventaja de TS.


8. Checklist: domina los tipos básicos

0/10 — 0% blindado

Conclusión

Los tipos básicos de TypeScript son sencillos: string, number, boolean, null, undefined, nada raro. Pero lo que de verdad hace especial a TypeScript es la inferencia porque no necesitas escribir tipos a mano el 90% del tiempo. TypeScript los deduce solo y te da autocompletado, protección contra errores y documentación automática gratis.

Piensa que cada vez que usas any, un gatito o perrito es sacrificado. any es el backdoor que destruye todo lo que TypeScript te ofrece. Si necesitas flexibilidad, usa unknown y verifica el tipo antes de usarlo.

En el próximo post veremos los tipos avanzados: type vs interface, tipos unión, intersección, tipos literales y mucho más. Ahí es donde TypeScript empieza a petarlo más aún.

EA, nos vemos en los bares 🍻


Pon a prueba lo aprendido

1. ¿Qué significa que TypeScript tiene tipado fuerte?

2. ¿Cuál es el tipo inferido de: let precio = 19.99?

3. ¿Qué pasa si haces let nombre = 'Domin' y luego nombre = 42?

4. ¿Cuál es el problema principal de usar any?

5. ¿Qué diferencia hay entre any y unknown?

6. ¿Cuándo deberías escribir el tipo explícitamente en lugar de dejar que TypeScript lo infiera?