Utility Types en TypeScript III: ReturnType, Parameters, InstanceType y Awaited

La tercera parte de los utility types cubre los que trabajan con funciones y clases en lugar de con objetos. ReturnType, Parameters, ConstructorParameters e InstanceType extraen información de tipos de funciones y clases. Awaited desenvuelve Promises anidadas. Juntos permiten componer tipos sin declararlos a mano, usando el propio código como fuente de verdad.

ReturnType: el tipo que devuelve una función

ReturnType<T> extrae el tipo de retorno de una función. Es útil cuando no controlas la declaración de la función, por ejemplo cuando viene de una librería:

function obtenerUsuario() {
  return { id: 1, nombre: "Ana", email: "[email protected]" };
}

type Usuario = ReturnType;
// { id: number; nombre: string; email: string }

// Útil con librerías externas
import { createStore } from "redux";
type TiendaRedux = ReturnType;

Parameters: los tipos de los parámetros

Parameters<T> devuelve una tupla con los tipos de todos los parámetros de la función:

function registrar(nombre: string, edad: number, activo?: boolean): void {}

type ParamsRegistrar = Parameters;
// [nombre: string, edad: number, activo?: boolean]

// Útil para wrappers y decoradores
function logear any>(
  fn: F,
  ...args: Parameters
): ReturnType {
  console.log("Llamando con:", args);
  return fn(...args);
}

ConstructorParameters: parámetros de un constructor

ConstructorParameters<T> hace lo mismo que Parameters pero para el constructor de una clase. Permite crear instancias de una clase de forma genérica:

class Conexion {
  constructor(
    private host: string,
    private puerto: number,
    private ssl: boolean = true
  ) {}
}

type ArgsConexion = ConstructorParameters;
// [host: string, puerto: number, ssl?: boolean]

function crearConexion(...args: ConstructorParameters): Conexion {
  return new Conexion(...args);
}

InstanceType: el tipo de instancia de una clase

InstanceType<T> devuelve el tipo de las instancias de una clase constructora. Es útil cuando trabajas con referencias a clases genéricas o con factories:

class Repositorio {
  buscarPorId(id: number): Promise {
    return Promise.resolve(null);
  }
}

type InstanciaRepo = InstanceType;
// Repositorio (el tipo de instancia, no de la clase)

function crearRepo any>(
  Clase: T,
  ...args: ConstructorParameters
): InstanceType {
  return new Clase(...args);
}

Awaited: desenvolver Promises anidadas

Awaited<T> extrae el tipo interior de una Promise, incluidas las Promises anidadas. Es el tipo equivalente a lo que obtienes al hacer await:

type A = Awaited>;               // string
type B = Awaited>>;       // number
type C = Awaited>;      // string | boolean

async function fetchDatos(): Promise<{ id: number; titulo: string }[]> {
  return fetch("/api/datos").then(r => r.json());
}

type Datos = Awaited>;
// { id: number; titulo: string }[]

Composición de utility types

Los utility types se pueden combinar. Un patrón habitual es usar Awaited con ReturnType para obtener el tipo resuelto de una función asíncrona:

async function obtenerArticulos() {
  const res = await fetch("/api/articulos");
  return res.json() as Promise<{ id: number; titulo: string }[]>;
}

type Articulos = Awaited>;
// { id: number; titulo: string }[]

// Ahora puedes usar Articulos en componentes sin redeclarar el tipo
function renderizarLista(articulos: Articulos): string {
  return articulos.map(a => a.titulo).join("n");
}

La regla general es: si tienes un valor en el código (una función, una clase, un objeto), usa typeof más uno de estos utility types para extraer el tipo que necesitas. Así el tipo siempre está sincronizado con la implementación real.

Imagen: Pexels / Myburgh Roux

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP