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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了'number'类型的参数不能分配给array.includes()中'never'类型的参数相关的知识,希望对你有一定的参考价值。

我从以下代码中收到打字错误。据推测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([]);
};
答案

为您的useState代替

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

您可以尝试

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

代替?

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

另一答案

问题

当具有不同类型的数组的并集时,不能在它们上调用方法。

原因

您有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[])
);
另一答案

问题

当具有不同类型的数组的并集时,不能在它们上调用方法。

原因

您有String(),因此String()是:

Number()

当TS合并这些签名时,它将把两个Number()签名结合在一起:

// Types
export interface IProductPrice {
  id: number
}

// State
const [productPrices, setProductPrices] = useState<IProductPrice[]>([])
const [selectedProductIds, setSelectedProductIds] = useState<(string|number)[]>([])

// Delete Selected Products
const deleteSelectedProducts = () => {
  setProductPrices(productPrices.filter(p => !selectedProductIds.filter(id => Number(id) === p.id).length))
  setSelectedProductIds([])
}

这有点不直观,但这简化为string[] | number[]。因为如果您有一个使用X的函数或一个使用Y的函数,那么传递的唯一安全的东西就是.filter ((filterFunc: (x: string) => boolean) => string[]) | ((filterFunc: (x: number) => boolean) => number[]) filterFunc

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

修复

理想情况下,您只会使用YX & Y,而不能同时使用。 (仅查看​​代码,为什么number & string只能是数字,而“选定的产品ID”也可以是字符串,这有点神秘)


但是如果您确实需要同时支持字符串和数字,那么这里最简单的解决方法是使用never而不是(x: never) => boolean:单个数组类型没有尝试将两个string[]签名合并在一起的问题。

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

number[]

这很简单,但是缺点是它允许混合使用字符串和数字组成的数组,这可能是不希望的。 (例如id


如果没有,您可以暂时转换为Array<string | number>,进行过滤,然后转换回string[] | number[]。这不是超级干净,但应该是安全的:

.filter

以上是关于'number'类型的参数不能分配给array.includes()中'never'类型的参数的主要内容,如果未能解决你的问题,请参考以下文章

参数类型“Type”不能分配给参数类型“FirebaseUser”

参数类型“PointerEvent”不能分配给参数类型“PointerDownEvent”

flutter error:参数类型'Future '无法分配给参数类型'小部件'

Typescript类型'string'不能分配给类型

参数类型列表无法分配给参数类型'LatLng'

在 swift 中将 String 类型数组转换为 Float 类型数组 不能将类型 'String' 的值分配给类型 'Double' 的下标。