为什么 Array.filter 的谓词返回类型是未知的(而不是布尔值)?

问题描述 投票:0回答:1

在 TypeScript 核心库中,

Array.filter
有两个签名:

filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];

filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];

我理解第一个签名——它让类型断言谓词缩小数组的类型。

但是,第二个签名似乎使谓词返回

boolean
而不是
unknown
。我知道 JS 比这更宽松,会将值强制转换为
boolean
,但 TypeScript 似乎通常不鼓励隐式转换。

将其更改为

boolean
似乎可以防止更多错误,即:

// Because the return type is unknown, TS silently accepts this unintentional number | boolean return type
[1,2,3,4,5].filter(el => someMap.get(el) ?? 0 > 1) // equivalent to someMap.get(el) ?? (0 > 1)

这个签名背后的理由是什么?

同样的问题适用于

some
any
,但不适用于
find

arrays typescript filter types ecmascript-5
1个回答
0
投票

filter
谓词只需要返回一个布尔值。由于 any 值可以在 JS 中强制转换为布尔值,这意味着它可以是任何类型:对我们来说它就是字面上的
unknown
。指定返回
boolean
会太狭窄:有效谓词将无法编译。

考虑一个接受所有非空字符串元素的过滤器:

let input: (string|undefined|null)[] = ["yeah", "", "okay", undefined, null];
let nonEmptyStrings = input.filter(x => x);

这个“清理”谓词是一种非常合理的过滤器,您在野外发现它不会感到惊讶。它是 JS 的“俚语”,表示更冗长、严谨的措辞,例如 ...

input.filter(x => x !=== null && x.length > 0)
input.filter(x => Boolean(x))
input.filter(x => !!x);

(我个人认为上面的第一行是改进,因为它的意图很明确。没有人会不确定是否要过滤掉空字符串。)

但在其他情况下,冗长是否有帮助则不太清楚,例如在检查属性是否存在时。比较这两个...

input.filter(x => x.someOptionalProperty) // not type safe, nice to read
input.filter(x => Object.hasOwnProperty('someOptionalProperty')) // type safe, yucky

不知道你,但我非常更喜欢前者。它更短,惯用,你可以 IDE 上下文(“去定义”)。

但比非布尔返回是否是“好风格”更重要的是,TS 的目标之一是提供 所有有效 JS 的结构化类型,而不是希望尘埃和蜘蛛网消失。过滤谓词可以有效地返回 any value 是没有争议的,所以结果确实必须是

unknown
.

(也许有一天 TS 会支持一个

booleanish
糖类型;像
unknown
但期望被解释为布尔值?这可能会使签名的动机更加清晰。)

© www.soinside.com 2019 - 2024. All rights reserved.