I'm receiving a Typescript error,
error TS2345: Argument of type 'number' is not assignable to parameter of type 'string & number'. Type 'number' is not assignable to type 'string'. 112
setProductPrices(productPrices.filter(
(p): boolean => !selectedProductIds.includes(p.id)));
^^^^
from the following code:
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([]);
};
The includes()
method is supposedly
expecting a parameter of 'never' while p.id
is a number. Does anyone know how to fix this?
The error "Argument of type string | undefined is not assignable to parameter of type string" occurs when a possibly undefined value is passed to a function that expects a string . To solve the error, use a type guard to verify the value is a string before passing it to the function.
ts(2322) arr[0] = 'a'; We declared an empty array and it got assigned a type of never[] . This type represents an array that will never contain any elements (will always be empty). To solve this, we have to explicitly type the empty array.
The never type represents the type of values that never occur. For instance, never is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns. Variables also acquire the type never when narrowed by any type guards that can never be true.
The error "Type is not assignable to type 'never'" occurs when we declare an empty state array with the useState hook but don't type the array. To solve the error, use a generic to type the state array, e.g. const [arr, setArr] = useState<string[]>([]) . Here is an example of how the error occurs.
When you have a union of arrays of different types, you can't call methods on them.
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
.
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[])
);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With