有人可以向我解释为什么在这种情况下:
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);
打字稿不再抱怨了?
答案 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
无论如何,希望能有所帮助。祝你好运!