1

I have a really weird issue:

TS2322: Type '(arg0: Person[]) => void' is not assignable to type '(arg0: Person | Person[]) => void'.

Wtf is going on here? Function parameter union type tells that it can be a array or not, but doesn't work. Looks like typescript bug?

This code calls it, error is shown on onAdd:

onAdd={(item: Person[]) => {
  const persons = item.map((el) => el.name);
}}

And the type of onAdd is this:

onAdd?: (person: Person| Person[]) => void;
5
  • Had a similar issue in the past, got a really thorough explanation why this is happening here: stackoverflow.com/a/58632009/5554464 Commented Nov 25, 2022 at 14:24
  • How did you solved it exacly? Maybe you can tell me how it should look like in my case? Commented Nov 25, 2022 at 14:27
  • Read through that question, it's a duplicate of this one. There is lengthy explanation of the reason, and I also posted my workaround for it as an answer. Commented Nov 25, 2022 at 14:31
  • 1
    Can you show us the code that caused this error? That error can legitimately happen. It means that the function must be written so it can accept either an array or an individual person, but the function only accepts arrays. Commented Nov 25, 2022 at 14:31
  • @NicholasTower the function accepts both currently with union Commented Nov 25, 2022 at 14:34

2 Answers 2

2

Typescript is pointing out a real issue in your code.

onAdd?: (entity: Person| Person[]) => void;

This type means that when you call onAdd, you might be passing in a Person, or you might be passing in a Person[]. No way to know in advance. As a result, any function that's passed as the onAdd prop needs to be able to handle both cases.

onAdd={(item: Person[]) => {
  const persons = item.map((el) => el.name);
}}

This function will break if called with an individual person. If item is an individual person, then it won't have a .map method, and you'll get a runtime exception. So, typescript detects that the functions are incompatible, and gives you the error.

The likely fix is to change your function so it can work with individual person objects:

onAdd={(item: Person | Person[]) => {
  const persons = Array.isArray(item) ? item.map(el => el.name) : [item.name];
}}

Another possibility is that (entity: Person | Person[]) => void; is not the type you meant, but in that case i'll need more information about what your goal is in order to suggest a solution.

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

2 Comments

@caTS Variance is the right concept, but the function arguments are contravariant, not covariant. In a normal context (ie, without involving functions), Person extends from Person | Person[]. Anything that's expecting a Person | Person[] can take a Person. If the function arguments were covariant, they would follow that same direction, and anything that's expecting a (item: Person | Person[]) => void could take a (item: Person) => void. But instead, the order is reversed
0

Just fix ur onAdd function to this:

onAdd={(item: Person | Person[]) => { const persons = Array.isArray(item) ? item.map(element => element.name) : [item.name]; }}

Comments

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.