馃攼 Programando tipos en Typescript – Parte II

En el post anterior comenzamos a definir nuevos tipos de datos din谩micamente en Typescript utilizando las herramientas del metalenguaje, principalmente con los tipos generics y el uso condicional de estos.

En este post observaremos otras utilidades que nos permiten extender nuestras definiciones de forma din谩mica.

Los ejemplos est谩n disponibles tambi茅n en este espacio de repl.it.

Keyof

El operador keyof nos permite obtener una uni贸n de las propiedades de un objeto.

type Person = {
  name: string;
  age: number;
  isAlive: boolean;
};

type PersonProperties = keyof Person; // "name" | "age" | "isAlive"

鈿狅笍 Algo muy importante es que en Typescript las propiedades de un objeto son siempre coaccionadas a un string. Esto implica que si se tiene un n煤mero como propiedad Typescript lo interpretar谩 como string. Para observarlo tambi茅n he creado este repl.it.

Typeof e infer

El operador typeof de Javascript nos permite inferir el tipo de datos a partir de un valor. Dado que estamos operando sobre valores esta utilidad produce una variable.

let myName = "Raymundo";

let nameType = typeof myName; //string

Typescript a帽ade un operador interno, infer, que opera de la misma manera que typeof en el contexto de un tipo de datos. Por ejemplo, usando infer podemos obtener el tipo de datos que una funci贸n retorna.

const getAnimal = () => ({ name: "perro", legs: 4 });

// Si T es una funci贸n: devuelve el tipo de datos que la funci贸n retorna
type MyReturnType<T> = T extends (...params: any) => infer R ? R : never;

// { name: string, legs: number }
type Animal = MyReturnType<typeof getAnimal>;

Si se observa correctamente la inferencia requiere tambi茅n del uso del operador typeof. Esto se debe a que con 茅l se puede obtener la firma de la funci贸n que determina su tipo, T, para que despu茅s pueda ser operado con infer mediante MyReturnType.

En este caso typeof sobre getAnimal retorna el tipo () => {name: string, legs: number} y al aplicar MyReturnType a este tipo obtenemos {name: string, legs: number }.

Acceso indexado de tipos

Typescript permite crear tipos a partir de propiedades de otros tipos.

Una forma de hacerlo es mediante el acceso a trav茅s de una propiedad espec铆fica

// string
type PersonName = Person["name"];
// number
type PersonAge = Person["age"];
// boolean
type PersonIsAlive = Person["isAlive"];

Tambi茅n podemos obtener la uni贸n de todos los tipos de datos que son manejados por un objeto mediante el acceso a trav茅s de keyof.

// Todos los tipos de datos para las propiedades de Person
// string | number | boolean
type PersonTypes = Person[keyof Person];

Al operar con arreglos de datos Typescript tiene un operador especial, number, que permite obtener la definici贸n del tipo de los elementos del arreglo.

const animals = [
  { name: "dog", legs: 4 },
  { name: "human", legs: 2 },
];

// { name: string, legs: number }
type Animal = typeof animals[number];

const beings = [
  { name: "dog", legs: 4 },
  { name: "broccoli", arms: 16 }
];

// { name: "string", legs: number, arms?: undefined } | { name: "string", arms: number, legs?: undefined }
type Beings = typeof beings[number];

Validando el registro de datos para un objeto

Con lo mencionado anteriormente podemos escribir una peque帽a funci贸n que validar谩 el tipo de datos antes de realizar la actualizaci贸n de un objeto.

function updateData<T>(prop: keyof T, value: T[keyof T], seed: T): T {
  if (typeof seed[prop] !== typeof value) {
    throw "tipo de datos incorrecto";
  }
  return {
    ...seed,
    [prop]: value,
  }
}

const seed: Person = {
  name: "Ray",
  age: 37,
  isAlive: true, // y coleando
};

// T como Person es inferido por Typescript mediante `seed`
const upd = updateData("name", "Raymundo", seed);

// Updated { name: 'Raymundo', age: 37, isAlive: true }
console.log("Updated", upd);

// Error: Argument of type location is not assignable
const incorrect = updateData("location", "Brussels", seed);

// esto produce un error: "tipo de datos incorrecto"
const wrong = updateData("age", "37", seed);

Como se observa la funci贸n updateData opera sobre un tipo de datos gen茅rico T y acepta solamente propiedades que est茅n defininas en T, as铆 como valores con el tipo de datos que les corresponde de acuerdo a su definici贸n.

Write a comment