tengo una situación redux compleja con la que estoy trabajando y no puedo obtener lo que necesito. Tengo 2 objetos, Track y Target
interface Track { id: number, ...other fields } interface Target { id: number (same as the Track) tracks: Track[] ...other fields }lo que estoy tratando de hacer es cuando busco las pistas, estoy tratando de ver si hay algún objetivo que tenga la misma ID (un objetivo para muchas pistas), y si es así, agregue la pista a la matriz de pistas de ese objetivo, de lo contrario - cree un nuevo objetivo con esa ID de pista y coloque la pista en la matriz de pistas
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] } ) ) ] }Creo que esto está en el camino correcto, pero mecanografiado se queja porque creo que tal vez está anidando cosas en un nivel demasiado profundo debido a los bucles anidados. Errores mecanografiados aquí
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",Como se indica en los comentarios, los targets de propiedad en su estado tienen el tipo Target[] , pero lo que le está asignando no lo es. state.targets.map(...) devuelve una matriz de objetivos, por lo que Target[] , luego se devuelve desde la función de devolución de llamada a otro map , por lo que action.tracks.map(...) devuelve una matriz de matrices de Target ( entonces Target[][] ) y luego lo envuelve entre un par de corchetes, por lo que se convierte en Target[][][] . La llamada a .map devuelve una matriz, por lo que si la envuelve entre llaves cuadradas, obtiene una matriz en una matriz, por lo que el primer paso es eliminarlas.
Ahora, para deshacerse de otro nivel de anidamiento, deberá deshacerse de .map , que no funcionará del todo en este caso, porque .map simplemente transforma una matriz en otra matriz con la misma longitud. Aquí la longitud puede variar, por lo que .map no encaja muy bien. La forma más sencilla es simplemente no usar métodos integrados e ir con un bucle:
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]}) } Tal vez podría hacer que este algoritmo sea un poco más rápido al no revisar toda la matriz de targets en cada iteración.
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] }) } } Si realmente desea algunos métodos integrados, .reduce encajaría mejor:
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 } )O si no te gustan los objetos mutantes
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), ] } )Pero no veo mucha ventaja en este código, porque no es muy legible y copia innecesariamente elementos entre arreglos tantas veces.