Проблема
Когда у вас есть объединение массивов разных типов, вы не можете вызывать методы для них.
Причина
У вас есть string[] | number[]
, и поэтому .filter
равно:
((filterFunc: (x: string) => boolean) => string[])
| ((filterFunc: (x: number) => boolean) => number[])
Когда TS объединяет эти подписи, он объединяет две filterFunc
подписи вместе:
((x: number) => boolean)
| ((x: string) => boolean)
Это немного не интуитивно понятно, но упрощается до (x: number & string) => boolean
. Потому что, если у вас есть функция, которая принимает X, или функция, которая принимает Y, единственная безопасная вещь, которую нужно передать, это то, что является одновременно X
и Y
, или X & Y
.
number & string
однако, это невозможный тип, который «упрощается» до never
. Поэтому подпись (x: never) => boolean
.
Исправление
В идеале вы должны использовать только string[]
или number[]
, но не оба. (Просто глядя на код, немного загадочно, почему id
может быть только числом, но «идентификаторы выбранного продукта» тоже могут быть строками)
Но если вам нужно поддерживать обе строки и числа, самое простое решение здесь - использовать Array<string | number>
вместо string[] | number[]
: у одного типа массива нет проблемы объединения двух сигнатур .filter
.
Вы можете изменить свое состояние на этот тип:
const [selectedProductIds, setSelectedProductIds] = useState<Array<string | number>>([]);
Это просто, но имеет недостаток в том, что он допускает массивы смешанных строк и чисел, которые могут быть желательно. (Например, setSelectProductIds(['0', 1, '2'])
Если нет, вы можете временно привести к Array<string | number>
, выполнить фильтр, а затем вернуть к string[] | number[]
. Это не супер чисто, но должно быть безопасно:
setProductPrices(
(productPrices as Array<string | number>).filter((p): boolean => !selectedProductIds.includes(p.id)) as (string[] | number[])
);