Bruno R

Todos los dias tipos

x
portfolio-next-l5vb64p5k-bandikyu.vercel.app

Sintaxis. Como definir tipos basando para el ejemplo los tipos primitivos, string, number, boolean. (Mas adelante se podran crear tipos personalizados)

Arrays

Para especificar el tipo de una matriz de numeros ([1, 2, 3]), puede usar la sintaxis number[]; esta sintaxis funciona para cualquier tipo (ej: string[] es una matriz de cadenas).

Tambien se puede escribir Array<number>, Array<string>.

Any

TypeScript tambien tiene un tipo especial de tipo de dato, any, que puede usar siempre que no desee que un valor en particlar cause errores de verificacion de tipos

Los tipo any son utilizados cuando no desea escribir un tipo de dato largo solo para convencer a TS que una linea de codigo es particular esta bien

noImplicitAny

Cuando no especifica un tipo, y TS no puede deducirlo del contexto, el compilador normalmente utilizara de manera predeterminada any.

Pero por lo general se querra evitar esto, porque any no tiene un verificador de tipo. Usar la bandera del compilador noImplicitAny para marcar cualquier any como un error.

(seguro tendre una configuracion en ts.config.json)

Escribir anotaciones como variables

Al declarar una variable opcionalmente puede agregar una anotacion de tipo, para especificar el tipo de variable:

let myName: string = "Bruno";

En la mayoria de los casos, declarar el tipo de dato no es necesario, ya que TS intenta inferir automaticamente los tipos que se usan en el codigo.

Funciones

TypeScript permite especificar los tipos de los valores de entrada y salida de las funciones.

Anotacion de tipo del parametro

Al igual que siempre, la declaracion del tipo va despues:

// Anotacion de 
tipo 
string en el parametro name
function greet(name: string) {
  console.log("hola, " + name.toUpperCase() + "!!");
}

Anotaciones de tipo en las devoluciones

Los tipos de retorno en una funcion se colocan despues de los parametros:

function getFavoriteNumber(name: string): number {
  return Number(name);
}

Funciones anonimas

Las funciones anonimas se definen distinto a las declaraciones de funciones. Cuando TS determina como sera llamada, los parametros de esta reciben automaticamente tipos.

// No hay anotaciones de tipo, pero TS puede detectar errores
const names = ["Alice", "Bob", "Eve"];
 
// Tipado contextual para la funcion
names.forEach(function (s) {
  console.log(s.
toUppercase
());
// Error: Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?

});
 
// El tipado contextual tambien funciona para las funciones de flecha
names.forEach((s) => {
  console.log(s.
toUppercase
());
// Error: Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?

});

Para entender el contexto y lograr un tipado al parametro s TS uso los tipos del foreach, junto con el tipo inferido de la matriz.

Este proceso se denomina tipificacion contextual, porque el contexto en el que se produjo la funcion informa que tipo debe tener.

Tipos de objetos

Aparte de los primitivos, el tipo mas comun es el tipo de objeto. Esto se refiere a cualquier valor de JS con propiedades, (que serian casi todas). Para definir un tipo de objeto (object type), simplemente enumeramos sus propiedades y sus tipos

Ejempo de una funciona que toma un objeto similar a un punto:

// La anotación de tipo del parámetro es un object type.
function printCoord(pt: { x: number; y: number }) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });

En el ejemplo se uso como parametro un object type con dos propiedades: x e y (ambos de tipo number).

Se puede usar , (coma simple) o ; (punto y coma), para separar las propiedades, y el ultimo separador es opcional.

Los tipos de datos agregador en las propiedades tambien son opcionales. Si no los definimos se usara por defecto el tipoany.

Propiedades opcionales ⚠️

Los object type tambien pueden especificar que algunas o todas sus propiedades sean opcionales.

Para lograr esto se debe agregar un “?”, despues del nombre de la propiedad:

function printName(obj: { first: string; last?: string }) {
  // ...
}
// Ambas opciones estan bien
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });

En JS, si accede a una propiedad que no existe, se obtiene undefinded en vez de un error de tiempo de ejecucion.

Por esta razon cuando lea una propiedad opcional, se tendra que buscar undefined antes de usarlo.

function printName(obj: { first: string; last?: string }) {
  // Error - Podria fallar si no se proporciona 'obj.last'
  console.log(obj.last.toUpperCase());

//Object is possibly 'undefined'.

  if (obj.last !== undefined) {
    // Esto corrije de posibles errores como el de arriba
    console.log(obj.last.toUpperCase());
  }
 
  //Para probar - Una alternativa segura que utiliza sintaxis moderna de JS:
  console.log(obj.last?.toUpperCase());
}

Tipos de Union

El sistema de tipos de TS permite crear nuevos tipos a partir de los existentes, utilizando una gran variedad de operadores.

Definicion de un tipo de union

La primer forma de combinar tipos es un tipo de union. Este es un tipo formado por dos o mas tipos de datos, por lo que el valor puede tener cualquiera de los tipos especificados en la union.

Cada entidad de estos tipos de datos unidos seria un miembro de la union

Ejemplo de funcion que puede tomar como parametro tanto number type como string type.

function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error
printId({ myID: 22342 });
// Argument of type '{ myID: number; }' is not assignable to parameter of 
type 'string | number'
.

Trabajo con tipos de union (union types)

TS solo permite una operacion si esta es valida para todos los miembros de la union. Ejemplo, si tiene una union string | number, no podra usar metodos que solo esten disponibles en string pero si podra usar metodos que esten disponibles en ambos miembros.

function printId(id: number | string) {
  console.log(id.toUpperCase());
/*Property 'toUpperCase' does not exist on type 'string | number'.
    Property 'toUpperCase' does not exist on type 'number'.*/

}

La solucion a esto seria estrechar la union por medio del codigo.

function printId(id: number | string) {
  if (typeof id === "string") {
    // En esta rama, la identificaciĂłn es del tipo 'cadena'
    console.log(id.toUpperCase());
  } else {
    // AquĂ­, la identificaciĂłn es del tipo 'nĂşmero'
    console.log(id);
  }
}

Ejemplo con array:

function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    // Aca: 'x' es 'string[]'
    console.log("Hello, " + x.join(" and "));
  } else {
    // Aca: 'x' es 'string'
    console.log("Welcome lone traveler " + x);
  }
}

Como se dijo antes, en algunos casos, puede que todos los miembros tengan metodos en comun, por lo que no sera necesario bifurcar la funcion segun el tipo de dato recibido de la union.

// El tipo de retorno se infiere como number[] | string
function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);
}

Tipos de alias (type alises)

Anteriormente se uso object types y union types escribiendolos directamente en anotaciones de tipo. Pero es comun el querer usar el mismo tipo mas de una vez y referirse a el por un solo nombre, esto se puede lograr con los type alises.

type Point = {
  x: number;
  y: number;
};
 
// Esto seria igual al 
ejemplo anterior

function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
 
printCoord({ x: 100, y: 100 });

Se puede utilizar un alias de tipo para dar nombre a cualquier tipo, no solo a tipos de objeto. Ejemplo, un alias de tipo puede nombrar un tipo de union (entonces cualquier tipo de dato definido puede ser nombrado)

type ID = number | string;

Interfaces

Una declaracion de interfaz es otra forma de nombrar un tipo de objeto

interface Point {
  x: number;
  y: number;
}
 
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
 
printCoord({ x: 100, y: 100 });

Al igual que cuando usamos alias de tipo, este codigo funciona como si hubieramos usado un tipo de objeto anonimo. TS solo se preocupa por la estructura del valor que le pasamos a printCoord, (osea que solo le importa que tenga las propiedades esperadas). Preocuparse solo por la estructura y las capacidades de los tipos es la razon por la que se llama a TypeScript un sistema de tipos estructuralmente tipado.

Diferencias entre alias de tipo e interfaces

Los alias de tipo y las interfaces son muy similares y, en muchos casos se pueden elegir entre ambas libremente. Casi todas las caracteristicas de una interface estan disponibles en type, la diferencias clave esta en que los type no se pueden volver a abrir para agregar nuevas propiedadesm frente a las interface que siempre son extensibles.

Algunas otras caracteristicas:

â–¸ Antes de la version 4.2 de TS, los nombre de los
â–¸ Lo que ya vimos, los
â–¸ Las interfaces solo se pueden usar para declarar las formas de los objetos, no para cambiar el nombre de las primitivas.

Tipos de aserciones (Type Assertions)

A veces tendremos informacion sobre el tipo de un valor que TS no puede conocer.

Ejemplo, si utilizamos document.getElementById, TS solo sabe que esto devolvera algun tipo de HTMLElement, pero es posible que sepamos que en la pagina siempre tendremos un HTMLCanvasElement mediante una identificacion dada.

En estas situaciones se puede usar una asercion de tipo para especificar un tipo mas especifico:

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;

Al igual que una notacion de tipo, el comilador elimina las aserciones de tipo por lo que esto no afectara el comportamiento en el tiempo de ejecucion del codigo.

En este caso tambien se puede usar la sintaxis de parentesis angular (excepto si el codigo esta en un archivo .tsx):

const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

TypeScript solo permite aserciones de tipo que se convierten en una version mas especifica o menos especifica de un tipo. Esta regla previene “imposibles” como:

const x = "hello" as number;

Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

A veces, esta regla puede ser demasiado conservadora (al buscar relaciones con los tipos) y no permitira coacciones complejas que podrian ser validas. Si esto sucede, se pueden usar dos aserciones, primero para llevarlo al tipo any (o unknown), luego al tipo deseado ⇒

const a = (expr as any) as T;
//expr seria el valor del tipo de dato que queramos y lo estamos llevando a un tipo any
// y luego lo pasamos a T que seria el tipo que queramos.
// Obviamente todo esto con los errores que conllevaria si la utilizamos mal