我个人会避免使用 Ramda 等人,因为根据我的经验,它们的类型不是很好。这是一个纯粹的 fp-ts 方法(Str.fromNumber 来自 fp-ts-std,被简单替换):
declare const arrayOfKeyNums: Option<Array<number>>
const arrayOfKeys = pipe(arrayOfKeyNums, O.map(A.map(Str.fromNumber)))
declare const record: Option<Record<string, number>>
const keyIntersectedVals: O.Option<Array<number>> = pipe(
sequenceT(O.Apply)(arrayOfKeys, record),
O.map(([ks, rec]) =>
pipe(
rec,
R.foldMapWithIndex(Str.Ord)(A.getMonoid<number>())((k, v) =>
A.elem(Str.Eq)(k)(ks) ? [v] : [],
),
),
),
)
由于需要传递类型类实例,因此有点冗长。从好的方面来说,使用 typeclass 实例意味着可以轻松更新它以支持任何值类型,包括具有任何给定 Eq 的非原始类型。
下面是在 Haskell 中的 body 可能看起来的比较,其中不需要传递 typeclass 实例:
keyIntersectedVals :: Maybe [Int]
keyIntersectedVals = uncurry (M.foldMapWithKey . intersectedToList) <$> sequenceT (mkeys, mmap)
where intersectedToList ks k v
| k `elem` ks = [v]
| otherwise = []
例如,给定键O.some(["a", "c"]) 和记录O.some({ a: 123, b: 456, c: 789 }),我们得到O.some([123, 789])。