带有过滤器方法的 TypeScript - 它无法正确推断 Array.isArray 的结果

我有一个关于过滤器在 TS 中如何工作的问题: 我有一个 Foo

类型的对象
type Foo = {
  foo: number[];
  bar: number[];
  lol: string;
};

const obj: Foo = {
  foo: [1,2,3],bar: [4,5],lol: "lol"
};

我需要过滤掉非数组值并提取数字

const re = Object.values(obj)
 .filter((val) => Array.isArray(val))
 .flatMap((num) => num);

console.log(re); //[1,3,4,5]

现场演示如下:https://codesandbox.io/s/hopeful-mclaren-x59u8?file=/src/index.ts 但是 TS 认为 .filter((val) => Array.isArray(val)) num 之后仍然可以是字符串,即它可以是 lol。它似乎不知道 .filter 是如何工作的。

即使没有 flatMap,如果我们检查 re 的类型,你会得到 const re: (string | number[])[] 意味着 re 仍然可能是一个字符串,这在这里不是真的,因为我们根据 Array.isArray 过滤掉它。

dwtmwyc 回答:带有过滤器方法的 TypeScript - 它无法正确推断 Array.isArray 的结果

Array.filter 返回调用它的相同数组类型。

但是您可以通过将过滤器函数设为 type predicate 来强制它更改类型,这让编译器知道此处返回 true 的真正含义。

const re = Object.values(obj)
  .filter((val): val is number[] => Array.isArray(val))
  .flatMap((num) => num); // now this works

console.log(re); //[1,2,3,4,5]
,

TS 不够聪明,无法知道“哦,您只过滤数组,Foo 上的数组类型都是 number[],因此过滤器的输出只会是 {{1 }}”。

有很多方法可以让编译器“知道”number[] 是一个数字。但是它涉及也知道这个事实并将它告诉编译器。还请记住,TS 仅在转译时有用。在 num 包含其他类型为 Foo 的数组的情况下,运行代码不会失败。

所以我不知道这是否有助于回答您的问题,但在您的示例中,我会做一些明确的事情,例如:

string[]

这样编译就知道 type Foo = { foo: number[]; bar: number[]; lol: string; }; const obj: Foo = { foo: [1,3],bar: [4,5],lol: "lol" }; const re = obj.foo.concat(obj.bar); console.log(re); // [1,5] re,你也一样。

如果您需要遍历 number[],那么 Foo 将保留类型。

for of
本文链接:https://www.f2er.com/337.html

大家都在问