从未定义的值过滤数组

时间:2019-05-15 11:54:03

标签: typescript

有人可以向我解释为什么在这种情况下:

const dataValues: ValueRange[] = res.data.valueRanges.filter((range: ValueRange) => range.values);

const formattedValues: Array<SheetData | undefined> = dataValues.map(this.formatSheetRanges);

const sheetData: Array<SheetData> = formattedValues.filter((sheetData: SheetData | undefined) => sheetDataGuard(sheetData));

function sheetDataGuard(data: SheetData | undefined): data is SheetData {
  return !!(<SheetData>data).user;
}

sheetData数组仍然会抱怨它的类型是

Array<SheetData | undefined>

但是如果我将最后一次过滤更改为:

const sheetData: Array<SheetData> = formattedValues.filter(sheetDataGuard);

打字稿不再抱怨了?

1 个答案:

答案 0 :(得分:2)

这是因为标准TypeScript库中的方法<TreeView ItemsSource="{Binding Source={StaticResource DocumentsCVS}}" PresentationTraceSources.TraceLevel="High"> <TreeView.ItemTemplate> <HierarchicalDataTemplate DataType="{x:Type vm:DocumentVM}"> <HierarchicalDataTemplate.ItemsSource> <Binding> <Binding.Source> <CollectionViewSource Source="{Binding Specs}"> <CollectionViewSource.SortDescriptions> <componentmodel:SortDescription PropertyName="position" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </Binding.Source> </Binding> </HierarchicalDataTemplate.ItemsSource> <HierarchicalDataTemplate.ItemTemplate> <DataTemplate DataType="{x:Type vm:SpecVM}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <fa:ImageAwesome Grid.Column="0" Icon="PuzzlePiece" Width="16" Margin="3,3,6,3" Foreground="Orange" /> <Label Grid.Column="1" Content="{Binding name}" /> </Grid> </DataTemplate> </HierarchicalDataTemplate.ItemTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <fa:ImageAwesome Icon="FileWordOutline" Height="16" Margin="3,3,6,3" Foreground="Crimson" /> <Label Grid.Column="1" Content="{Binding name}" /> </Grid> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> 的类型为overload signature,如果已知回调函数为user-defined type guard,则该类型专门缩小返回的数组元素类型:

Array<T>.filter()

由于 interface Array<T> { filter<S extends T>( callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any ): S[]; } 的类型可分配给sheetDataGuard,因此在以(value: SheetData | undefined, index: number, array: Array<SheetData | undefined>) => value is SheetData作为filter参数的Array<SheetData | undefined>上调用sheetDataGuard导致编译器选择为callbackfn推断的SheetData重载。

但是,当您改为使用S进行调用时,该函数的类型将被推断为仅返回(sheetData: SheetData | undefined) => sheetDataGuard(sheetData)。这是因为用户定义的类型保护功能do not propagate and are not inferred for you。像boolean这样的类型通常在您开始使用它时就被编译器扩展为x is Y

通过使用箭头函数返回类型注释,您可以告诉编译器箭头函数回调也是一种类型保护,

boolean

编译器应该很高兴。当然,如果要执行此操作,则最好不要将const sheetData: Array<SheetData> = formattedValues.filter( (sheetData: SheetData | undefined): sheetData is SheetData => sheetDataGuard(sheetData) ); 定义为单独的函数:

sheetDataGuard

无论如何,希望能有所帮助。祝你好运!