Anotaciones de tipo e inferencia

Básico
TypeScript
TypeScript
Actualizado: 04/05/2026

Diagrama: tutorial-typescript-anotaciones-tipo-inferencia

Sintaxis de anotaciones de tipo

Una anotación de tipo indica al compilador el tipo de dato que puede contener una variable, un parámetro o un valor de retorno. La sintaxis consiste en dos puntos seguidos del nombre del tipo, colocados después del identificador:

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

console.log(nombre, edad, activo);

La anotación : string declara que la variable nombre solo puede contener valores de tipo cadena de texto. Si se intenta asignar un valor de otro tipo, el compilador genera un error:

let precio: number = 49.99;
// Error: Type 'string' is not assignable to type 'number'
// precio = "cuarenta y nueve";
console.log(precio);

Las anotaciones de tipo solo existen durante la compilación. El JavaScript generado no contiene ninguna información de tipos.

Anotaciones en funciones

En las funciones, las anotaciones se aplican a cada parámetro y al valor de retorno:

function calcularImpuesto(base: number, porcentaje: number): number {
  return base * (porcentaje / 100);
}

const impuesto = calcularImpuesto(1000, 21);
console.log(impuesto);

El tipo de retorno se coloca después del paréntesis de cierre de los parámetros. Si la función no devuelve ningun valor, se utiliza void:

function mostrarMensaje(texto: string): void {
  console.log(texto);
}

mostrarMensaje("Operación completada");

Anotaciones en funciones flecha

Las funciones flecha siguen la misma sintaxis:

const duplicar = (n: number): number => n * 2;

const saludar = (nombre: string): string => {
  return `Hola, ${nombre}`;
};

console.log(duplicar(5));
console.log(saludar("Carlos"));

Cuando se asigna una función flecha a una variable con tipo declarado, los parámetros pueden omitir sus anotaciones porque TypeScript los deduce del contexto:

type Operación = (a: number, b: number) => number;

const sumar: Operación = (a, b) => a + b;
const restar: Operación = (a, b) => a - b;

console.log(sumar(10, 3));
console.log(restar(10, 3));

Tipos primitivos

TypeScript reconoce todos los tipos primitivos de JavaScript y permite usarlos como anotaciones de tipo.

string, number y boolean

Los tres tipos primitivos más comunes:

const titulo: string = "Aprende TypeScript";
const cantidad: number = 42;
const disponible: boolean = true;

console.log(titulo, cantidad, disponible);

El tipo number abarca enteros, decimales, hexadecimales, binarios y octales:

const entero: number = 100;
const decimal: number = 3.14;
const hexadecimal: number = 0xff;
const binario: number = 0b1010;
const octal: number = 0o744;

console.log(entero, decimal, hexadecimal, binario, octal);

null y undefined

En TypeScript, null y undefined son tipos propios. Con la opción strictNullChecks activada, no se pueden asignar a otros tipos sin declararlo explícitamente:

let valor: string | null = "texto";
valor = null; // Valido porque el tipo incluye null

let opcional: number | undefined = undefined;
opcional = 42; // Valido

console.log(valor, opcional);

Sin la union explícita, asignar null o undefined a una variable de otro tipo genera un error:

let nombre: string = "Ana";
// Error: Type 'null' is not assignable to type 'string'
// nombre = null;
console.log(nombre);

Con strictNullChecks activado, TypeScript obliga a manejar explícitamente los casos donde un valor puede ser null o undefined. Esto previene la categoría más común de errores en JavaScript.

symbol

El tipo symbol representa valores únicos e inmutables, creados con la función Symbol():

const id: symbol = Symbol("identificador");
const otro: symbol = Symbol("identificador");

console.log(id === otro); // false: cada Symbol es único
console.log(typeof id);

bigint

El tipo bigint permite trabajar con enteros de precisión arbitraria, útiles para cálculos que exceden el rango seguro de number:

const grande: bigint = 9007199254740991n;
const suma: bigint = grande + 1n;

console.log(suma);
console.log(typeof suma);

Los valores bigint se crean con el sufijo n después del literal numérico. No se pueden mezclar number y bigint en operaciones aritmeticas.

any y unknown

TypeScript proporciona dos tipos especiales para situaciones donde el tipo exacto no se conoce. Aunque ambos aceptan cualquier valor, su comportamiento es fundamentalmente diferente.

El tipo any

El tipo any desactiva completamente la verificación de tipos. Una variable de tipo any se puede usar como si fuera de cualquier tipo, sin que el compilador genere errores:

let dato: any = "texto";
dato = 42;
dato = true;
dato = { clave: "valor" };

// Todo esto es válido con any, aunque sea peligroso
console.log(dato.metodoInexistente);
console.log(dato.propiedad.anidada);

El compilador no verifica ninguna operación sobre variables any. Esto significa que los errores solo se detectaran en tiempo de ejecución, anulando la principal ventaja de TypeScript.

function procesarAny(datos: any): any {
  // TypeScript no verifica nada aquí
  return datos.nombre.toUpperCase();
}

// Compila sin errores, pero falla en ejecución si datos no tiene .nombre
console.log(procesarAny({ nombre: "Ana" }));

El tipo any debe evitarse en código nuevo. Existe principalmente para facilitar la migración gradual desde JavaScript y para interactuar con bibliotecas sin definiciones de tipos.

El tipo unknown

El tipo unknown es la alternativa segura a any. Acepta cualquier valor, pero obliga a verificar el tipo antes de utilizarlo:

let entrada: unknown = "texto";

// Error: 'entrada' is of type 'unknown'
// console.log(entrada.toUpperCase());

// Solucion: verificar el tipo primero
if (typeof entrada === "string") {
  console.log(entrada.toUpperCase()); // TypeScript sabe que es string aquí
}

Con unknown, TypeScript exige una comprobación explícita antes de permitir cualquier operación específica del tipo:

function procesarEntrada(valor: unknown): string {
  if (typeof valor === "string") {
    return valor.toUpperCase();
  }
  if (typeof valor === "number") {
    return valor.toFixed(2);
  }
  return String(valor);
}

console.log(procesarEntrada("hola"));
console.log(procesarEntrada(3.14159));
console.log(procesarEntrada(true));

Comparación práctica entre any y unknown

// Con any: peligroso, no hay verificación
function parsearJSON_any(texto: string): any {
  return JSON.parse(texto);
}

const datos_any = parsearJSON_any('{"nombre": "Ana"}');
console.log(datos_any.nombre); // Funciona, pero sin verificación
// datos_any.metodoFalso(); // Compilaria sin error, falla en ejecución

// Con unknown: seguro, requiere verificación
function parsearJSON_unknown(texto: string): unknown {
  return JSON.parse(texto);
}

const datos_unknown = parsearJSON_unknown('{"nombre": "Ana"}');
// console.log(datos_unknown.nombre); // Error: Object is of type 'unknown'

// Se necesita verificación
if (typeof datos_unknown === "object" && datos_unknown !== null && "nombre" in datos_unknown) {
  console.log((datos_unknown as { nombre: string }).nombre);
}

El tipo void

El tipo void indica que una función no devuelve ningun valor significativo. Es el tipo de retorno implícito de funciones que no tienen sentencia return o que usan return sin valor:

function registrar(mensaje: string): void {
  console.log(`[LOG] ${mensaje}`);
}

function notificar(usuario: string, evento: string): void {
  console.log(`Notificacion para ${usuario}: ${evento}`);
  return; // return sin valor es válido con void
}

registrar("Inicio de la aplicación");
notificar("Ana", "nuevo mensaje");

Declarar variables de tipo void no es útil en la práctica. El uso principal de void es como tipo de retorno de funciones y como tipo de retorno en firmas de callbacks:

type Callback = (resultado: string) => void;

function ejecutarConCallback(tarea: string, cb: Callback): void {
  const resultado = `Tarea "${tarea}" completada`;
  cb(resultado);
}

ejecutarConCallback("compilar", (msg) => {
  console.log(msg);
});

Inferencia de tipos

TypeScript no requiere anotar cada variable y cada retorno. El motor de inferencia deduce automáticamente los tipos cuando hay suficiente información contextual. Esto reduce la cantidad de anotaciones necesarias sin perder seguridad.

Inferencia en variables

Cuando una variable se inicializa con un valor, TypeScript infiere el tipo a partir de ese valor:

const mensaje = "Hola mundo";      // tipo inferido: string
const cantidad = 100;               // tipo inferido: number (con let sería number)
const activo = true;                // tipo inferido: boolean (con let sería boolean)
const elementos = [1, 2, 3];        // tipo inferido: number[]
const mixto = [1, "dos", true];     // tipo inferido: (string | number | boolean)[]

console.log(mensaje, cantidad, activo, elementos, mixto);

Con const, TypeScript infiere tipos literales más estrechos para primitivos:

const estado = "activo";  // tipo: "activo" (literal)
let fase = "inicio";      // tipo: string (mas amplio, porque let permite reasignacion)

console.log(estado, fase);

Inferencia en funciones

El tipo de retorno de una función se infiere a partir de sus sentencias return:

function calcularDescuento(precio: number, porcentaje: number) {
  return precio * (1 - porcentaje / 100); // retorno inferido: number
}

function obtenerEtiqueta(código: number) {
  if (código === 1) return "activo";
  if (código === 2) return "inactivo";
  return "desconocido"; // retorno inferido: string
}

console.log(calcularDescuento(100, 15));
console.log(obtenerEtiqueta(1));

Los parámetros de funciones no se infieren y deben anotarse (excepto en contextos donde TypeScript tiene información del tipo esperado, como callbacks):

const números = [10, 20, 30, 40];

// El parámetro 'n' se infiere como number porque números es number[]
const dobles = números.map(n => n * 2);
console.log(dobles);

// El parámetro 'n' se infiere como number, el parámetro 'i' como number
const indexados = números.map((n, i) => `${i}: ${n}`);
console.log(indexados);

Cuándo anotar y cuándo dejar que infiera

La recomendación práctica es:

  • Anotar siempre los parámetros de funciones públicas y los tipos de retorno complejos.
  • Dejar que infiera los tipos de variables locales cuando el tipo es evidente por el valor asignado.
  • Anotar explícitamente cuando la inferencia produce un tipo más amplio del deseado.
// Anotación necesaria: parámetros de función
function filtrarPorMinimo(valores: number[], minimo: number): number[] {
  return valores.filter(v => v >= minimo);
}

// Anotación innecesaria: el tipo es evidente
const resultado = filtrarPorMinimo([5, 10, 15, 20], 12);
console.log(resultado);

// Anotación útil: la inferencia sería demasiado amplia
const configuración: { modo: "desarrollo" | "producción"; puerto: number } = {
  modo: "desarrollo",
  puerto: 3000
};
console.log(configuración);

Inferencia contextual

TypeScript utiliza el contexto para inferir tipos en funciones anónimas y callbacks. Cuando una función se pasa como argumento a otra función cuyo tipo de parámetro está definido, los tipos se propagan automáticamente:

type Transformador = (valor: string) => string;

function aplicar(textos: string[], fn: Transformador): string[] {
  return textos.map(fn);
}

// Los parámetros de la función anonima se infieren del tipo Transformador
const mayusculas = aplicar(["hola", "mundo"], (valor) => valor.toUpperCase());
console.log(mayusculas);

// También funciona con métodos de array
const nombres = ["Ana", "Carlos", "Elena"];
const longitudes = nombres.map(nombre => nombre.length); // nombre inferido como string
console.log(longitudes);

La inferencia contextual es una de las razones por las que TypeScript resulta menos verboso de lo que podría parecer. En muchas situaciones, el compilador tiene suficiente información para deducir los tipos sin anotaciones explícitas.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TypeScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de TypeScript

Explora más contenido relacionado con TypeScript y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Utilizar la sintaxis de anotaciones de tipo con : type en variables, parámetros y valores de retorno. Conocer los tipos primitivos de TypeScript: string, number, boolean, null, undefined, symbol y bigint. Comprender la diferencia entre any y unknown y cuando usar cada uno. Aplicar la inferencia de tipos para reducir anotaciones innecesarias. Utilizar void para funciones que no devuelven valor.