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

时间:2020-02-14 22:46:41

标签: reactjs typescript react-hooks

我从以下代码中收到打字错误。据推测includes()方法 p.id是数字时,期望参数'never'。有人知道如何解决这个问题吗?

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([]);
};

2 个答案:

答案 0 :(得分:7)

问题

当您拥有不同类型的数组的并集时,就无法在它们上调用方法。

原因

您有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的函数,那么传递的唯一安全的事情就是XYX & Y两者。

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

修复

理想情况下,您只会使用string[]number[],而不能同时使用两者。 (仅看代码,为什么id只能是数字,而“选定的产品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[])
);

答案 1 :(得分:2)

为您的useState而不是

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

你能尝试

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

相反?

这是因为在将selectedProductIds设置为字符串数组的地方可能缺少一些代码。在您的代码中,您已严格将其定义为1个数组,而不是另一个。也许上述更改可以解决此问题。请确认。