Búsqueda de sitios web

Cómo definir el tipo de argumento aceptado por objeto para una función en TypeScript


Digamos que quiero definir una función que acepte un argumento que debe ser un objeto cuyas claves sean cadenas y los valores puedan ser, por ejemplo, number | string como se hace en el ejemplo de abajo.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

const p = {
  id: 1,
  name: 'John'
};

fn(p);

El ejemplo anterior funcionará perfectamente, pero cuando quiero dar un tipo explícito a la variable p usando type de TypeScript como en el ejemplo de abajo, todo vuelve a funcionar perfectamente.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

type User = {
  id: number;
  name: string;
}

const p: User = {
  id: 1,
  name: 'John'
};

fn(p);

Pero al definir un tipo con el interface de TypeScript como en el ejemplo a continuación, estoy recibiendo un error que dice
TS2345: El argumento de tipo 'User' no se puede asignar al parámetro de tipo 'Record<string, string | number>'.
Falta la firma de índice para el tipo 'string' en el tipo 'User'.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

interface User {
  id: number;
  name: string;
}

const p: User = {
  id: 1,
  name: 'John'
};

fn(p);

¿Entonces cuál es la razón de tal comportamiento? ¿Cómo puedo definir el tipo para el argumento de una función para que sea un objeto cuyas claves deban ser string y los valores puedan ser un tipo unión, por ejemplo string | number, y que funcione con ambos types y interfaces?

Respuesta #1

Esto debería deberse al hecho de que las interfaces están "abiertas" mientras que los alias de tipo están cerrados, lo que significa que no se pueden extender después de su declaración inicial, a diferencia de las interfaces, que pueden ser declaradas nuevamente, lo que significa que podrías agregar propiedades a la interfaz, que no son asignables a Record<string, string | number>. Esto también se relaciona con la fusión de declaraciones

Consulta este patio de juegos para más detalles

Respuesta #2

REVISADO:

Puedes desestructurar el objeto p de la siguiente manera al llamar a la función:

fn({ ...p });

Esto toma todas las propiedades de p y las coloca en un nuevo objeto.

También es posible crear un nuevo objeto con el propósito de pasarlo a la función:

const params = {
    ...p,
};

fn(params);