从未定义的值中过滤数组

Mar*_*cin 3 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;
}
Run Code Online (Sandbox Code Playgroud)

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

Array<SheetData | undefined>
Run Code Online (Sandbox Code Playgroud)

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

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

Run Code Online (Sandbox Code Playgroud)

打字稿不再抱怨了吗?

jca*_*alz 5

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

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

由于 的类型sheetDataGuard可分配给(value: SheetData | undefined, index: number, array: Array<SheetData | undefined>) => value is SheetData,因此调用filterwithArray<SheetData | undefined>作为sheetDataGuard参数将导致编译器使用推断的 forcallbackfn选择该重载。SheetDataS

但是,当您使用 with 调用(sheetData: SheetData | undefined) => sheetDataGuard(sheetData)它时,该函数的类型会被推断为仅返回boolean。这是因为用户定义的类型保护函数不会传播,也不会为您推断。一旦您开始使用类似的类型,编译器x is Y通常会对其进行扩展。boolean

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

const sheetData: Array<SheetData> = formattedValues.filter(
    (sheetData: SheetData | undefined): sheetData is SheetData =>
        sheetDataGuard(sheetData)
);
Run Code Online (Sandbox Code Playgroud)

编译器应该很高兴。当然,如果您打算这样做,您最好忘记定义sheetDataGuard为单独的函数:

const sheetData: Array<SheetData> = formattedValues.filter(
(sheetData: SheetData | undefined): sheetData is SheetData =>
    !!sheetData
);
Run Code Online (Sandbox Code Playgroud)

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