arraystypescriptobjectreducetslint

Unable to type function to retrieve values from nested objects using array values


// nested object
const obj = {
  one: {
    two: {
      three: 'xxxx',
    },
    four: {
      five: 5,
    },
    six: [1, 2, 3],
  },
}

I want to get a value from the above nested object using key.

The sample below works in javascript, but I can't define the type properly in typescript.

const result = ['one', 'two', 'four'].reduce(
  (acc, key) => acc[key],
  obj,
)
// undefined

const result = ['one', 'two', 'three'].reduce(
  (acc, key) => acc[key],
  obj,
)
// xxxx

const result = ['one', 'six'].reduce(
  (acc, key) => acc[key],
  obj,
)
//  [1, 2, 3]

tslint

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ one: { two: { three: string; }; four: { five: number; }; six: number[]; }; }'. No index signature with a parameter of type 'string' was found on type '{ one: { two: { three: string; }; four: { five: number; }; six: number[]; }; }'.ts(7053)

I understand that the type checking does not work because "one" in the array is a string and the key from reduce is "one". However, I can't think of a solution. Please let me know what type definition would work.


Solution

  • If you defined a type which is a record with a string key and any value:

    type kv = Record<string,any>;
    

    Then your original object is itself a record with a string key, and either another kv or any value:

    const obj : Record<string, kv | any> = {
      one: {
        two: {
          three: 'xxxx',
        },
        four: {
          five: 5,
        },
        six: [1, 2, 3],
      },
    }
    

    Then your warnings go away Live example