Group orders with Ramda I made some crude code using RamdaJS to essentially group orders by their states. There are some nested structures. Currently, I have a working code, but I wondering if Ramda can perhaps help to clean that up more? I've added TypeScript annotations to present (simplified) structures more clearly.

I've also prepared codesandbox with example data: https://codesandbox.io/s/yqwm2p65zz

import * as R from 'ramda'

export default function(orders: Order[], orderListing: OrderListing[]) {
  const pluckStateEnum = (orderState: OrderState) =&gt; orderState.enum

  const ordersByState = (states: OrderStateEnum[]) =&gt;
    orders.filter(
      (order: Order) =&gt;
        !R.isEmpty(
          R.intersection(R.map(pluckStateEnum, order.orderStates), states),
        ),
    )

  return orderListing.map(listing =&gt; ({
    id: listing.id,
    orders: ordersByState(listing.orderStateEnums).map(order =&gt; order.id),
  }))
}

interface Order {
  id: string
  orderStates: OrderState[]
}

interface OrderState {
  enum: OrderStateEnum
}

interface OrderListing {
  id: string
  orderStateEnums: OrderStateEnum[]
}

type OrderStateEnum =
  | 'RECEIVED'
  | 'PAID'
  | 'UNPAID'
  | 'CUSTOMER_NOTIFIED'
  | 'FINISHED'
First, a couple Typescript notes:


I assume you cannot change the data format, if you can, I would highly recommend renaming the enum property. enum is a keyword in Typescript.
OrderStateEnum should be represented as an actual enum. I'd also consider dropping the Enum suffix.

enum OrderStateEnum {
  RECEIVED = 'RECEIVED',
  PAID = 'PAID',
  UNPAID = 'UNPAID',
  CUSTOMER_NOTIFIED = 'CUSTOMER_NOTIFIED',
  FINISHED = 'FINISHED'
}

Avoid default exports - see Typescript Deep Dive


You are correct, Ramda can help simplify this code. 


pluckStateEnum is equivalent to R.prop('enum')
ordersByState can have the nesting level reduced, additionally, checking if the intersection of two arrays is empty can be better represented with R.any(R.contains(R.__, arr1), arr2). I also use chain to flatten the array while getting properties.

const ordersByState = states =&gt; orders.filter(R.pipe(
  R.prop('orderStates'), 
  R.chain(R.prop('enum')),
  R.any(R.contains(R.__, states))
))


With this change, the function becomes much easier to read. See the repl.


For completeness, here is how I would implement this function:

function group(orders, orderListing) {
  const ordersByState = states =&gt; orders.filter(R.pipe(
    R.prop('orderStates'), 
    R.chain(R.prop('enum')), // you might know this as flatMap
    R.any(R.contains(R.__, states))
  ))

  return orderListing.map(listing =&gt; ({
    id: listing.id,
    orders: ordersByState(listing.orderStateEnums).map(R.prop('id')),
  }))
}