Búsqueda de sitios web

typescript - ¿Puedes crear un tipo mapeado que asigne claves a valores?


Supongamos que tengo una colección de funciones como esta:

const myFuncs = {
  appendFoo: (s: string) => `${s}FOO`,
  addFive: (n: number) => n + 5,
}

Los tipos mapeados me permiten hacer cosas interesantes como crear un tipo genérico para una colección de argumentos mapeados a una o más funciones en myActions, así:

type MyFuncInputs = Partial<{ [k in keyof typeof myFuncs]: Parameters<typeof myFuncs[k]>[0] }>

...pero esto hace que la estructura del objeto que puedo describir con ese tipo genérico sea bastante rígida. Supongamos, por ejemplo, que myFuncs es una colección de manejadores para un reductor, y quiero crear un tipo genérico que describa una acción para ese reductor.

Lo siguiente no es TypeScript válido, pero con suerte ilustrará lo que me gustaría hacer:

type MyAction = {
  type: [k in keyof typeof myFuncs],
  payload: Parameters<typeof myFuncs[k]>[0]
}

¿Hay alguna manera de crear algo así?

Lo más cerca que he llegado es esto, pero me encantaría encontrar una manera de inferir el valor de F a partir del type del objeto en lugar de tener que especificarlo dos veces:

type MyAction<F extends keyof typeof myFuncs> = {
  type: F,
  payload: Parameters<typeof myFuncs[F]>[0] 
}

const fooAction: MyAction<'appendFoo'> = {
  type: 'appendFoo',
  payload: 'bar'
}

const addAction: MyAction<'addFive'> = {
  type: 'addFive',
  payload: 1
}

¡Gracias a cualquiera que pueda ayudar!

Respuesta #1

Parece que solo quieres una forma de asegurarte de que la propiedad 'type' y el tipo de propiedad 'payload' de tu acción sean compatibles con una de las funciones en tu objeto myFuncs. Una manera de hacer esto sería usar tipos de unión y tipos mapeados.

Por ejemplo:

type MyAction = { [K in keyof typeof myFuncs]: { type: K, payload: Parameters<typeof myFuncs[K]>[0] } }[keyof typeof myFuncs];

const fooAction: MyAction = {
  type: 'appendFoo',
  payload: 'bar'
}

const addAction: MyAction = {
  type: 'addFive',
  payload: 1
}

Es decir, estamos generando un tipo mapeado donde cada clave K de myFuncs se asigna a un objeto correspondiente con las propiedades 'type' y 'payload', transformando el tipo mapeado en un tipo unión donde un objeto puede ser cualquiera de los objetos definidos en el tipo mapeado.

Referencia: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html