Menu

Inferencia de tipos en TypeScript: cuándo anotar y cuándo no

TypeScript deduce la mayoría de los tipos a partir de los valores que escribes. Aprende qué infiere para variables, let frente a const, objetos, arrays y valores de retorno, cómo los callbacks reciben sus tipos del contexto y dónde sigues necesitando una anotación.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

La inferencia de tipos es TypeScript deduciendo un tipo que no escribiste. Inicializa una variable y toma el tipo del valor; devuelve un valor desde una función y el tipo de retorno se deduce solo. La mayor parte del código TypeScript lleva muchas menos anotaciones de lo que la gente espera.

Los comentarios muestran lo que enseña un editor al pasar el cursor por cada nombre. La última línea es un error de compilación (TS2322) aunque count nunca se anotó; // @ts-expect-error la marca como esperada para que el resto del bloque se ejecute.

let frente a const: ensanchamiento de literales

Una const no puede cambiar nunca, así que TypeScript le da el tipo más estrecho: el propio valor literal. Una let recibe el tipo más amplio, porque puede reasignarse más tarde.

let a = "left";    // string
const b = "left";  // "left"
let c = 42;        // number
const d = 42;      // 42
const e = true;    // true

Esto importa cuando una función solo acepta ciertos valores:

index.ts(7,6): error TS2345: Argument of type 'string' is not assignable to parameter of type '"left" | "right"'.

Arréglalo con const o anotando la variable: let dir: "left" | "right" = "left". Los tipos literales tienen su propia página, tipos literales.

Objetos y arrays ensanchan sus miembros

Las propiedades de un objeto literal son mutables, así que se ensanchan como con let, incluso cuando el objeto en sí es const. Los elementos de un array hacen lo mismo. as const lo vuelve todo readonly y conserva los tipos literales.

Inferencia del tipo de retorno

El tipo de retorno de una función se infiere a partir de sus sentencias return. Cuando hay varias, el resultado es la unión de todas.

Los tipos de retorno inferidos sirven para la mayoría de funciones. Escribe el tipo de retorno de forma explícita en funciones exportadas o públicas cuando quieras que la firma sea un contrato: si un cambio en el cuerpo devuelve otro tipo, el error aparece en la función y no en alguna llamada lejana.

Tipado contextual: los callbacks reciben sus tipos

Los parámetros no se infieren a partir de cómo se llama una función. Hay dos excepciones. Un parámetro con valor por defecto toma el tipo de ese valor (function retry(times = 3) hace que times sea number). Y una función escrita donde ya se espera un tipo de función recibe los tipos de sus parámetros de ese contexto, así que los parámetros de un callback no necesitan anotación.

Lo mismo vale para forEach, filter, reduce, los callbacks de Promise, los manejadores de eventos y cualquier función que pases a un parámetro con un tipo de función declarado.

Los parámetros necesitan anotaciones

Sin un valor por defecto ni un contexto como ese, TypeScript no mira cómo se llama una función para adivinar los tipos de sus parámetros. Con strict activado, un parámetro sin anotar es el error TS7006:

index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type.

Escribe function double(x: number) y el bloque imprime 42, con el tipo de retorno number inferido de x * 2.

Mejor tipo común

Para un array literal con valores de distinta clase, TypeScript infiere un array de la unión de sus tipos. No busca un tipo base compartido que no hayas mencionado.

El array vacío es el único caso a vigilar. const list = [] empieza como un array «evolutivo» cuyo tipo crece con cada push; una anotación, const list: string[] = [], deja clara la intención desde el principio y se entiende mejor.

Cuándo anotar

Situación¿Anotar?
Variable inicializada con un valorNo, el valor da el tipo
Variable declarada sin valor (let result;)Sí, let result: string;
Parámetros de funciónSí (salvo callbacks con contexto o un valor por defecto)
Tipo de retorno de una función interna pequeñaOpcional
Tipo de retorno de una función exportada o públicaRecomendable, como contrato
Array u objeto vacío que llenas despuésSí, const ids: number[] = []
El valor debe conservar sus tipos literalesUsa as const
El valor debe cumplir un tipo pero conservar su propio tipo inferidoUsa satisfies

La forma más rápida de ver qué se infirió es pasar el cursor por el nombre en tu editor. Sin editor, asigna el valor a una variable de un tipo incorrecto, como const probe: boolean = mixed;, y el mensaje de error del compilador nombra el tipo inferido.

Preguntas frecuentes

¿Qué es la inferencia de tipos en TypeScript?

Es el compilador deduciendo un tipo que no escribiste. let count = 0 le da a count el tipo number, y una función que devuelve a + b con dos números recibe el tipo de retorno number. El tipo inferido se comprueba exactamente igual que uno escrito.

¿Debo anotar todas las variables en TypeScript?

No. Anota los parámetros de las funciones (no se infieren de las llamadas, solo de un valor por defecto o del contexto de un callback), los tipos de retorno de las funciones exportadas si quieres una API estable y las variables declaradas sin valor. Deja que TypeScript infiera el resto: const name: string = "Ada" repite lo que el compilador ya sabe.

¿Por qué const infiere un tipo literal y let infiere string?

Una const nunca se puede reasignar, así que const dir = "left" recibe el tipo literal "left". Una let podría guardar más tarde cualquier otra cadena, así que let dir = "left" se ensancha a string. Lo mismo ocurre con las propiedades de un objeto literal, porque las propiedades se pueden reasignar; as const lo evita.

¿Por qué TypeScript dice que un parámetro tiene implícitamente el tipo 'any'?

Es el error TS7006 de noImplicitAny, que forma parte de strict. TypeScript no infiere los tipos de los parámetros a partir de cómo se llama la función, así que un parámetro sin tipo sería any. Añade una anotación, function double(x: number), o pasa la función donde su tipo se conoce por el contexto, por ejemplo como callback de map.

¿Cómo puedo ver el tipo que infirió TypeScript?

Pasa el cursor por encima del nombre en tu editor (VS Code y la mayoría de editores muestran el tipo inferido en un tooltip). En el código, asignar el valor a una variable de un tipo claramente incorrecto hace que el compilador muestre el tipo inferido en su mensaje de error.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR