Ramda.js pluck(key) type vs native map

777 Views Asked by At

Say I have the following code:

const results = //some complex datastructure generated by a third party api call
const reducedList = results.map((item) => item.awesome_key)
  .map((awesomeKeyList) => awesomeKeyList
    .reduce((memo, awesomeKey) => {//stuff},{})))

This code works like a charm. Now say I decided to use Ramda for the first map through pluck like so:

  import R from Ramda;
  R.pluck('awesome_key', results)
    .map((awesomeKeyList) => awesomeKeyList
      .reduce((memo, awesomeKey) => {},{})))

This will fail with:

Property 'reduce' does not exist on type '{}'.

The types on Ramda.pluck are:

pluck<T>(p: string|number, list: any[]): T[];
pluck(p: string|number): <T>(list: any[]) => T[];

What about those types prevents me from using reduce in this manner?

An example (simplified) structure:

things: [
  {
    awesome_key: [{
      long_name: 'string',
      short_name: 'string',
      types: {
        0: 'string from set',
        1?: 'string'
      }
    }]
    other_fields not relevant here
    }
]
1

There are 1 best solutions below

0
On

Starting with this:

const results = [
  {
    awesome_key: [{
      long_name: 'foo',
      short_name: 'bar',
      types: {
        0: 'abc',
        1: 'def',
        2: 'ghi'
      }
    }, {
      long_name: 'baz',
      short_name: 'qux',
      types: {
        0: 'pqr',
        1: 'xyz'
      }
    }],
    other_fields: 'not relevant here'
    }
]
const interestingTypes = ['pqr', 'xyz'];

these two both have the same behavior, as far as I can tell:

results.map((item) => item.awesome_key)
  .map((addressComponentList) => addressComponentList.reduce((memo, addressComponent) => {
     if (interestingTypes.indexOf(addressComponent.types[0]) !== -1) {
       if (!memo[addressComponent.types[0]]) {
         memo[addressComponent.types[0]] = addressComponent.long_name
       }  
     }
     return memo
   },{}));

R.pluck('awesome_key', results)
  .map((addressComponentList) => addressComponentList.reduce((memo, addressComponent) => {
     if (interestingTypes.indexOf(addressComponent.types[0]) !== -1) {
       if (!memo[addressComponent.types[0]]) {
         memo[addressComponent.types[0]] = addressComponent.long_name
       }  
     }
     return memo
   },{}));

as does this, which is a little more idiomatic for Ramda:

R.pipe(
  R.pluck('awesome_key'),
  R.map(reduce((memo, addressComponent) => {
     if (interestingTypes.indexOf(addressComponent.types[0]) !== -1) {
       if (!memo[addressComponent.types[0]]) {
         memo[addressComponent.types[0]] = addressComponent.long_name
       }  
     }
     return memo
   },{}))
)(results) 

Obviously this could probably be cleaned up a bit too, but I'm basing the code on your other question.

pluck('field', xs) really should return the same sort of value as xs.map(x => x.field).

The typescript signatures you list are not how I think of pluck, which is documented as :: k -> [{k: v}] -> [v], meaning that it accepts a (String) key and a list of Objects containing that key, returning a list of values