How to use reduce with typescript to populate a typed array?

Viewed 35

I have an array of objects which is populated with objects generated by a reduce loop. These objects already have a type, hence I need the object generated by reduce to have the same type, but I'm strugling with the initial value of the reduce, since it is an empty object.

How can I set a type to the initial object without getting an error saying that the object is missing properties?

Interface and base value:

const productFormLocal = [
   {
      field: 'id',
      config: {
         elementType: false,
         value: '',
         validation: {},
         valid: true,
         touched: false
      }
   },
   {
      field: 'nome',
      config: {
         elementType: 'input',
         elementConfig: {
            type: 'text',
            placeholder: 'Nome do Produto',
            name: 'nome',
         },
         label: 'Nome do Produto',
         value: '',
         validation: {
            required: true,
         },
         valid: false,
         touched: false
      }
   }
]    

interface ProductsList {
   id: number
   nome: string
   qtde: number
   valor: number
   valorTotal: number
}

const productsList: ProductsList[] = []

For instance, if I do that I get the reduce working fine, but I wouldn't be able to push the generated objects to the array:

const data: Record<string, any> = {}

const productValues = productFormLocal.reduce((obj, item) => (
  obj[item.field] = item.config.value, obj
), data)

productsList.push(productValues)

And if I do that I would get an error saying that data is missing the ProductList properties:

const data: ProductsList = {}

const productValues = productFormLocal.reduce((obj, item) => (
  obj[item.field] = item.config.value, obj
), data)

productsList.push(productValues)

How could I solve this? I looked a lot but I coudn't find a way to get this right.

I know I could set all properties of ProductsList as optional, but it doesn't seem to be the best approach.

1 Answers

Set the reduce generic type, which will type the default value as well as the reducer function return type.

const productValues = productFormLocal.reduce<Record<string, any>>((acc, item) => ({
  ...acc,
  [item.field]: item.config.value
}), {})
Related