1

I want to update an object state with a function updateDatas. I pass key, potentially subKey, and value as argument of this function.

interface Datas {
  code: number;
  item1: Item;
}

interface Item {
  id: number;
  name: string;
}

const [datas, setDatas] = useState({
  code: 42,
  item1: {
    id: 1,
    name: 'foo'
  }
});

function updateDatas(key: string, subKey: string, value: any) {
  if (subKey) {
    setDatas({...datas, key: {...datas.key, subKey: value}});
  } else {
    setDatas({...datas, key: value});
  }
}

updateDatas('code', 23);
updateDatas('item1', 'name', 'bar');

But it doesn't work, I have this Typescript error :

Argument of type '{ key: any; code: number; item1: Item; }' is not assignable to parameter of type 'SetStateAction'. Object literal may only specify known properties, and 'key' does not exist in type 'SetStateAction'.ts(2345)

1
  • I think you have to wrap key and subKey in square brackets setDatas({...datas, [key]: {...datas.key, [subKey]: value}}); Commented Oct 9, 2020 at 12:47

1 Answer 1

2

You are trying to update the key subKey instead of using the key the variable subKey has as string. Same with key. Do the following:

function updateDatas(key: string, subKey: string, value: any) {
  if (subKey) {
    setDatas({...datas, [key]: {...datas[key] as Item, [subKey]: value}});
  } else {
    setDatas({...datas, [key]: value});
  }
}

Anyway you should have some incongruence between interfaces because key is of type string instead of keysof Datas and the same with subKey (keysof Item).

function updateDatas(key: keysof Datas, subKey: keysof Item, value: any) {
  if (subKey) {
    setDatas({...datas, [key]: {...datas[key], [subKey]: value}});
  } else {
    setDatas({...datas, [key]: value});
  }
}

EDIT: The same with the value, since in your interfaces you want the value to be other thing instead of any. You should look for a workaround around this.

Sign up to request clarification or add additional context in comments.

6 Comments

...datas.key give ts error : Property 'key' does not exist on type 'Datas'.. ...datas[key] doesn't work too.
Spread types may only be created from object types. ts(2698)
Oh yes because you should type better the params of your function since it can be any string key, hence TS doesn't know if that datas[key] is an object to spread, since i.e. datas.code is 42. Check my response please
I have made changes (keysof doesn't work for me, but keyof yes) : function updateDatas(key: keyof Datas, subKey: keyof Item, value: string | number) But datas[key] still doesn't work
The value could be of type string | number | Item but still isn't well typed. I would try another approach instead of having this all wrapped in one function. I don't know your use case but it might be other way. Please consider creating another question and mark the answer as correct if it is suitable
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.