Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

224
Vistas
Nested array maps inside of reducer

have a complex redux situation I am working with and cant quite get what I need. I have 2 objects, Track and Target

interface Track {
  id: number,
  ...other fields
}

interface Target {
  id: number (same as the Track)
  tracks: Track[]
  ...other fields
}

what I am trying to do is when I fetch the tracks I am trying to see if there are any targets that have the same ID (one target to many tracks), and if it does then add the track to that target's tracks array, otherwise - create a new target with that Track id and put the track in the tracks array

case TargetActionTypes.FETCH_TARGETS_SUCCESS:
  return {
    ...state,
    targets: [
      action.tracks.map((track: Track) =>
        state.targets.map((target: Target) =>
          track.target_id === target.id
            ? {
                ...target,
                tracks: [...target.tracks, track]
              }
            : {
                id: track.target_id,
                visible: true,
                tracks: [track]
              }
        )
      )
    ]
  }

I think this is on the right track but typescript is complaining because I think maybe its nesting things one level too deep because of the nested loops? Typescript errors here

Types of property 'targets' are incompatible. Type '{ tracks: Track[]; id: number; visible: boolean; }[][][]' is not assignable to type 'Target[]'.
Type '{ tracks: Track[]; id: number; visible: boolean; }[][]' is missing the following properties from type 'Target': id, visible, tracks",

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

As stated in comments, property targets in your state has type Target[], but what you are assigning to it is not. state.targets.map(...) returns an array of targets, so Target[], then it is returned from callback function to another map so action.tracks.map(...) returns an array of arrays of Target (so Target[][]) and then you are wrapping it in a pair of square brackets, so it becomes Target[][][]. Call to .map returns an array, so if you wrap it in square braces, you get array in array, so the first step is to remove those.

Now to get rid of another level of nesting you will need to get rid of .map, which won't quite work in this case, because .map just transforms one array to another array with the same length. Here the length can vary, so .map is not a very good fit. The simplest way is just not using built-in methods and going with a loop:

const targets: Target[] = []
for(const track of tracks) {
  const target = targets.find(target => target.id === track.target_id)

  if (target) target.push(track)
  else targets.push({id: track.target_id, visible: true, tracks: [track]})
}

Maybe you could make this algorithm a little faster by not going over the entire array of targets in every iteration

const targets: Target[] = []
const cache: Record<number, Target> = {}

for(const track of tracks) {
  if(track.target_id in cache) {
    cache[track.target_id].tracks.push(track)
  } else {
    targets.push(cache[track.target_id] = {
      id: track.target_id, 
      visible: true, 
      tracks: [track]
    })
  }
}

If you really want some built-in methods then .reduce would fit better:

tracks.reduce<Target[]>(
  (targets, track) => {
    const target = targets.find(target => target.id === track.track_id)

    if(!target) {
      targets.push({id: track.target_id, visible: true, tracks: [track]})
    } else {
      target.tracks.push(track)
    }
    return targets
    
  }
)

Or if you don't like mutating objects

tracks.reduce<Target[]>(
  (targets, track) => {
    const index = targets.findIndex(target => target.id === track.target_id)

    if(index < 0) {
      return [...targets, {id: track.target_id, visible: true, tracks: [track]}]
    } 
    return [
      ...targets.slice(0, index),
      {...targets[index], tracks: [...targets[index].tracks, track]},
      ...targets.slice(index),
    ]
  }
)

But I don't see much advantage in this code, because it is not very readable and unnecessarily copies elements between arrays so many times

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda