首页 > 解决方案 > 从未定义的值中过滤数组

问题描述

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

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);

打字稿不再抱怨了吗?

标签: typescript

解决方案


这是因为Array<T>.filter()标准 TypeScript 库中方法的类型具有重载签名,如果已知回调函数是用户定义的类型保护函数,则该签名专门缩小返回的数组元素类型:

 interface Array<T> {
   filter<S extends T>(
     callbackfn: (value: T, index: number, array: T[]) => value is S, 
     thisArg?: any
   ): S[];
 }

由于 of 的类型sheetDataGuard可分配给(value: SheetData | undefined, index: number, array: Array<SheetData | undefined>) => value is SheetData,因此调用withfilter作为参数将导致编译器选择带有inferred for 的重载。Array<SheetData | undefined>sheetDataGuardcallbackfnSheetDataS

但是当你调用它时(sheetData: SheetData | undefined) => sheetDataGuard(sheetData),该函数的类型被推断为 return just boolean。那是因为用户定义的类型保护函数不会传播,也不会为您推断。一旦你开始使用它,编译器就会将类似的类型x is Y扩展到它。boolean

您可以通过使用箭头函数返回类型注释告诉编译器您的箭头函数回调也是类型保护,如下所示:

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

编译器应该很高兴。当然,如果你要这样做,你不妨忘记定义sheetDataGuard为一个单独的函数:

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

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


推荐阅读