← Back to home

Typescript: Inferencia de tipo y tipado explicito

Cover Image for Typescript: Inferencia de tipo y tipado explicito
5 min readLevel:

Como ya debes saber, Typescript añade tipado estático opcional a JavaScript. Esto nos permite usar tipos. Por ejemplo, en este código:

main.ts
let name = 'Eric'

En el momento en el que asignamos un valor a una variable, TypeScript intenta inferir el tipo en la inicialización. En ese caso, el tipo de la variable name es string por inferencia.

Error: El tipo `number` no es asignable al tipo `string`

Como puedes ver, TypeScript nos avisa que estamos mezclando tipos. TypeScript usa un concepto conocido como inferencia de tipo para avisarnos de los errores no deseados.

La inferencia de tipo es la deducción automática de los tipos de datos de una expresión específica en un lenguage de programación.

Por otro lado, en JavaScript, se puede assignar diferentes valores y valores de diferentes tipos. JavaScript no se preocupa del tipo.

main.js
let name = 'Eric';
name = 123;

En la mayoría de casos, la inferencia de tipo es algo simple. ¿Cómo los tipos pueden ser inferenidos en los casos complejos? Hay dos situaciones especiales que necesitan más detalle: Best common type (algo así como Tipo común más adecuado) y Contextual typing (algo así como Tipado contextual).

Best common type

El 'Best common type' se calcula cuando el tipo es inferido usando varias expresiones. El tipo de esas expresiones es usado para inferir el tipo de la variable. Por ejemplo, en este código:

main.typescript
let x = [0, 1, false, true, "false", "true"];

TypeScript considera el tipo de cada elemento del arreglo para inferir el tipo de la variable x. En ese caso, el tipo de cada elemento del arreglo puede ser number, boolean o string.

El algoritmo para averiguar el tipo común más adecuado considera cada candidato del tipo y elige el tipo que es compatible con todo el abanico de posibilidades.

Tipo inferido en el arreglo

En algunos casos, el tipo común más adecuado no es suficientemente estricto o específico por lo que a veces te puede interesar tener un mayor control y definir algo más estricto. Para hacer tal cosa, necesitarás tipar específicamente con tipado estricto (BooleanValuesStrict):

Valores booleanos con declaración de tipo estricta

Con eso, somos capaces de ser más específicos y estrictos en nuestro tipado.

En algunos casos, no podemos depender de la inferencia y necesitamos hacer un tipado explícito para proveer de más robustez a nuestro código.

Como se puede ver, si usamos tipado explícito, estamos asegurando que sólo valores específicos estén permitidos y por eso TypeScript nos lanza un error.

Tipado explícito es útil cuando TypeScript no tiene suficiente contexto para inferir el tipo. Aún así, usarlo siempre puede hacerlo redundante, creando un código excesivamente recargado.

Añadir anotaciones de tipado explícito a todas las variables y funciones es redundante y no tiene ningún tipo de beneficio.

main.ts
const gretting = (msg: string, name: string): string => {
    const grettings: string = `${msg} ${name}`;
    return grettings;
}

const message: string = 'Hello';
const grettings: string = gretting(message, 'visitor');

console.log(grettings)

El código anterior es repetitivo y además podemos conseguir los mismos resultados cuando inferimos los tipos. Este código es más legible y preferible:

main.ts
const gretting = (msg: string, name: string) => {
    const grettings = `${msg} ${name}`;
    return grettings;
}

const message = 'Hello';
const grettings = gretting(message, 'visitor');

console.log(grettings)

Hay casos en los que el tipo común más adecuado puede ser simplificado usando un tipo super de todos los candidatos. Por ejemplo, podemos definir 3 tipos: Course, OnlineCourse and PresentialCourse.

main.ts
interface Course {
    id: string;
    name: string;
    description: string;
    date: string;
    places: number;
}

interface OnlineCourse extends Course {
    link: string;
}

interface PresentialCourse extends Course {
    address: string;
    room: string;
}

const reactCourse: OnlineCourse = {
    id: '123',
    name: 'React Course 2022',
    description: 'Intro to React',
    date: "Jul 15 2022",
    places: 50,
    link: 'www.ealch.dev/react-course',
};

const angularCourse: PresentialCourse = {
    id: '124',
    name: 'Angular Course 2022',
    description: 'Intro to Angular',
    date: "Jul 15 2022",
    places: 15,
    address: '123 Street',
    room: '1-2'
}

TypeScript puede inferir el tipo de curso (Course) si hacemos tipado en el lado izquierdo de la asignación ("left-side hand") de los elementos del arreglo:

Arreglo de OnlineCourse y PresentialCourse

Cuando TypeScript no es capaz de realizar el tipado común más adecuado, la inferencia resultante es la unión de los tipos del arreglo. De todos modos, podemos hacer tales cosas como:

Arreglo de OnlineCourse y PresentialCourse con tipado left-side hand

Contextual typing

El tipado contextual ocurre cuando el tipo de una expresión es implícito por su localización. Por ejemplo, en este código:

El validador de tipo ha usado el tipo de la función Window.onclick para inferir el tipo de la función en el lado derecho ("right-hand side") de la asignación. El validador de tipo pudo inferir el tipo del parámetro event, el cual no contiene la propiedad name.

Podemos intentar tipar el parámetro como NamedMouseEvent:

Pero esto no funcionará ya que rompe el tipado de Window.onclick:

Para solventar esto, nosotros tenemos, al menos, dos opciones diferentes:

El tipado contextual se aplica en muchos casos. De hecho, el tipado contextual puede actuar como un tipo candidato del "Best common type".

Puedes encontrar más información en la sección de Type inference.

If you find any kind of error, something that it's not clear enough or you want me to drill down in more detail, don't hesitate to contact me.