score:13

Accepted answer

The Problem

When you have a union of arrays of different types, you can't call methods on them.

The Reason

You have string[] | number[], and so .filter is:

  ((filterFunc: (x: string) => boolean) => string[]) 
| ((filterFunc: (x: number) => boolean) => number[])

When TS combines those signatures, it's going to union the two filterFunc signatures together:

  ((x: number) => boolean) 
| ((x: string) => boolean)

This is a little unintuitive, but this simplifies to (x: number & string) => boolean. Because if you have a function that take X, or a function that takes Y, the only safe thing to pass is something that is both X and Y, or X & Y.

number & string however, is an impossible type, which "simplifies" to never. Hence why the signature is (x: never) => boolean.

The Fix

Ideally you'd only use string[] or number[] but not both. (Just looking at the code, it's a little mysterious why id can only be number, but "selected product ids" can be strings, too)


But if you do need to support both strings and numbers, the easiest fix here is to use Array<string | number> instead of string[] | number[]: the single array type doesn't have the issue of trying to union together two .filter signatures.

You can either change your state to be of that type:

const [selectedProductIds, setSelectedProductIds] = useState<Array<string | number>>([]);

This is simple, but has the downside that it will allow arrays of mixed strings and numbers, which may not be desirable. (e.g. setSelectProductIds(['0', 1, '2'])


If not, you can temporarily cast to Array<string | number>, do the filter, then cast back to string[] | number[]. This is not super clean, but should be safe:

setProductPrices(
    (productPrices as Array<string | number>).filter((p): boolean => !selectedProductIds.includes(p.id)) as (string[] | number[])
);

score:3

For your useState instead of

const [selectedProductIds, setSelectedProductIds] = useState<string[] | number[]>([]);

Can you try

const [selectedProductIds, setSelectedProductIds] = useState< (string|number)[]>([]);

instead?

This is because there is probably some missing code where you've set selectedProductIds as an array of string. And in your code you've strictly defined it as 1 array and not the other. Maybe the above change fixes that. Kindly confirm.


Related Query

More Query from same tag