'number' 类型的参数不能分配给 array.includes() 中类型 'never' 的参数

Eri*_*rin 6 typescript reactjs react-hooks

我收到来自以下代码的打字稿错误。includes()据说该方法需要一个“从不”参数,而它p.id是一个数字。有谁知道如何解决这一问题?

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([]);
};
Run Code Online (Sandbox Code Playgroud)

Ret*_*sam 13

问题

当你有不同类型数组的联合时,你不能对它们调用方法。

原因

你有string[] | number[],所以.filter是:

  ((filterFunc: (x: string) => boolean) => string[]) 
| ((filterFunc: (x: number) => boolean) => number[])
Run Code Online (Sandbox Code Playgroud)

当 TS 组合这些签名时,它会将两个filterFunc签名合并在一起:

  ((x: number) => boolean) 
| ((x: string) => boolean)
Run Code Online (Sandbox Code Playgroud)

这有点不直观,但这简化为(x: number & string) => boolean. 因为如果你有一个接受 X 的函数,或者一个接受 Y 的函数,唯一安全的传递是既是Xand Y, or 的东西X & Y

number & string然而,是一种不可能的类型,它“简化”为never. 因此为什么签名是(x: never) => boolean.

修复

理想情况下,您只使用string[]number[]不使用两者。(单看代码,有点莫名其妙为什么id只能是数字,但是“selected product ids”也可以是字符串)


但是,如果您确实需要同时支持字符串和数字,那么这里最简单的解决方法是使用Array<string | number>而不是string[] | number[]:单个数组类型不存在尝试将两个.filter签名结合在一起的问题。

您可以将您的状态更改为该类型:

const [selectedProductIds, setSelectedProductIds] = useState<Array<string | number>>([]);
Run Code Online (Sandbox Code Playgroud)

这很简单,但有一个缺点,它允许混合字符串和数字的数组,这可能是不可取的。(例如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[])
);
Run Code Online (Sandbox Code Playgroud)