我正在尝试从数组过滤器中缩小(推论)我想要的类型,但这给了我TypeError:'Item'缺少以下属性
type ItemList = (Item | ItemGroup )[];
type ItemGroup = {
name: string;
items: Item[];
}
type Item = {
key: string;
label: string;
}
const list: ItemList = [
{
key: 'key',
label: 'label'
},
{
name: 'name',
items: [
{
key: 'key1',
label: 'label2'
},
{
key: 'key3',
label: 'label4'
},
]
}
]
const groups: ItemGroup[] = list.filter( l => 'name' in l )
^^^^^^
// Type '(Item | ItemGroup)[]' is not assignable to type 'ItemGroup[]'.
// Type 'Item | ItemGroup' is not assignable to type 'ItemGroup'.
// Type 'Item' is missing the following properties from type 'ItemGroup': name, items ts(2322)
有什么想法吗?
答案 0 :(得分:1)
不幸的是,编译器不够聪明,无法查看l => "name" in l
回调并理解可以将Item | ItemGroup
缩小为ItemGroup
。幸运的是,您可以通过将其注释为user-defined type guard function来告诉编译器:
const isItemGroup = (l: Item | ItemGroup): l is ItemGroup => "name" in l;
现在,如果您调用isItemGroup(l)
并且结果为true
,则编译器将了解l
是ItemGroup
。此外,标准库提供了一个call signature for Array.prototype.filter()
,它接受用户定义的类型保护回调并产生一个缩小的数组。因此,通过使用isItemGroup
作为回调,您将获得所需的结果:
const groups: ItemGroup[] = list.filter(isItemGroup); // no error now
答案 1 :(得分:1)
您有一个包含Item
和ItemGroup
元素的数组。您希望将此数组过滤为仅包含ItemGroup
的元素,并且希望打字稿理解您已过滤列表并知道返回的类型为ItemGroup[]
。
您可以通过将过滤器l => 'name' in l
变成其自己的类型保护功能来实现。返回类型value is ItemGroup
告诉打字稿“如果且仅当为true时,值的类型为ItemGroup”。
const isItemGroup = (value: Item | ItemGroup): value is ItemGroup => 'name' in value;
const groups: ItemGroup[] = list.filter( isItemGroup );
通过使用类型保护,打字稿可以理解list.filter
的含义,并且错误会消失。
答案 2 :(得分:0)
您可以使用type assertion断言过滤后的结果数组的类型为ItemGroup[]
:
const groups: ItemGroup[] = list.filter( l => 'name' in l ) as ItemGroup[]