Home > Net >  What is the proper way to access an object inside state using a key?
What is the proper way to access an object inside state using a key?

Time:06-15

I am building an app in React Typescript and I have a state defined like so:

  const [products, setProducts] = useState({
    fruits: [],
    veggies: [],
    herbs: [],
  });

When I want to add a product from an HTML select, let's say a fruit, I will call the following in the onChange function:

addProduct("fruits", value);

Where the function addProduct looks something like below. I am using productType as a key to access the specific product type in products:

const addProduct = (productType: string, value: string) => {
  setProducts((products) => ({
    ...products,
    [productType]: [...products.productType, value],
  }));
}

However, I am getting this error (screenshot attached to link): TS2339: Property 'productType' does not exist on type '{ fruits: never[]; veggies: never[]; herbs: never[]; }'. where ...products.productType is highlighted.

I've tried accessing ...products.productType using the dollar sign identifier, template literals but to no avail. How can I access ...products.productType? Is there a correct syntax to use, or is there a hacky solution around this?

EDIT: Thank you for the suggestions on defining the types, I will take that into consideration. However, I think this is the underlying issue:

"TS2339: Property 'productType' does not exist on type 'IState'".

If I try to access ...products.productType, it won't let me because productType does not exist in my products state. How can I get it to search for the string literal (which, in this example, is "fruits")?

CodePudding user response:

I will recommend keeping 3 different states instead of using only one. That will be way more flexible and easy to use and understand (for you and others devs touching your code).

In case you still want to do it that way, what is happening to you is that typescript is inferring the types from your initial values, which are empty arrays = never[]. To fix this you should type your state like:

interface IState {
  fruits: string[], // use whatever value it should be, I'm just guessing its a string
  veggies: string[],
  herbs: string[],
}

const [products, setProducts] = useState<IState>({
    fruits: [],
    veggies: [],
    herbs: [],
  });


const addProduct = (productType: keyof IState, value: string) => {
  setProducts((products) => ({
    ...products,
    [productType]: [...products[productType], value],
  }));
}

EDIT: Note that there are 2 more errors

  • producType should not be of type string but a key of IState
  • If you access an object with dot notation then TS expects the object to have that exact key. Instead, you should use bracket notation.

CodePudding user response:

There are some things wrong with your code like @super mentioned, you need to fix those as well. As for reason behind the issue you are getting is because you are trying to access the productType property of the old state using products.productType.

The property you are trying to access does not exists which is causing the issue and giving you the error.

To access the old states values to concat in value array change your code as below,

setProducts((products) => ({
   ...products,
   [productType]: [...products[productType], value],
}));

This should fix your issue.

EDIT

After change in code to include types for the state object the change was needed is given by @toni's answer.

  • Related