reactjs - Argument av typ 'number' kan inte tilldelas till parameter av typ 'never' i array.includes()
Jag får ett Typescript-fel,
fel TS2345: Argument av typen 'number' kan inte tilldelas parametern av typen 'string & number'. Typen 'number' kan inte tilldelas typen 'string'. 112
setProductPrices(productPrices.filter(
(p): boolean => !selectedProductIds.includes(p.id)));
^^^^
från följande kod:
export interface IProductPrice {
id: number;
}
const [productPrices, setProductPrices] = useState<IProductPrice[]>([]);
const [selectedProductIds, setSelectedProductIds] = useState<string[] | number[]>([]);
const deleteSelectedProducts = (): void => {
setProductPrices(productPrices.filter((p): boolean => !selectedProductIds.includes(p.id)));
setSelectedProductIds([]);
};
Metoden includes() förväntas tydligen en parameter av typen 'never' medan p.id är ett nummer. Vet någon hur man kan fixa detta?
Svar #1
Problemet
När du har en förening av arrayer av olika typer kan du inte anropa metoder på dem.
Anledningen
Du har string[] | number[], och därför är .filter:
((filterFunc: (x: string) => boolean) => string[])
| ((filterFunc: (x: number) => boolean) => number[])
När TS kombinerar de signaturerna kommer det att förena de två filterFunc-signaturerna tillsammans:
((x: number) => boolean)
| ((x: string) => boolean)
Detta är lite ologiskt, men detta förenklas till (x: number & string) => boolean. För om du har en funktion som tar X, eller en funktion som tar Y, är det enda säkra att skicka något som är både X och Y, eller X & Y.
number & string är dock en omöjlig typ, som "förenklas" till never. Därför är signaturen (x: never) => boolean.
Lösningen
Idealt sett skulle du bara använda string[] eller number[] men inte båda. (Bara genom att titta på koden är det lite mystiskt varför id bara kan vara ett nummer, men "valda produkt-id" också kan vara strängar)
Men om du behöver stödja både strängar och siffror, är det enklaste sättet här att använda Array<string | number> istället för string[] | number[]: den enskilda array-typen har inte problemet med att försöka slå ihop två .filter-signaturer.
Du kan antingen ändra ditt tillstånd till att vara av den typen:
const [selectedProductIds, setSelectedProductIds] = useState<Array<string | number>>([]);
Detta är enkelt, men har nackdelen att det tillåter arrayer med blandade strängar och nummer, vilket kanske inte är önskvärt. (t.ex. setSelectProductIds(['0', 1, '2'])
Om inte, kan du tillfälligt kasta till Array<string | number>, göra filtret, och sedan kasta tillbaka till string[] | number[]. Detta är inte superrent, men borde vara säkert:
setProductPrices(
(productPrices as Array<string | number>).filter((p): boolean => !selectedProductIds.includes(p.id)) as (string[] | number[])
);
Svar #2
För din useState istället för
const [selectedProductIds, setSelectedProductIds] = useState<string[] | number[]>([]);
Kan du försöka
const [selectedProductIds, setSelectedProductIds] = useState< (string|number)[]>([]);
istället?
Detta beror förmodligen på att det saknas kod där du har satt selectedProductIds som en array av strängar. Och i din kod har du strikt definierat det som ena arrayen och inte den andra. Kanske åtgärdar ändringen ovan det. Vänligen bekräfta.
