0

我是函数式编程的新手,但想学习最佳实践。

将数组转换为对象的正确 fp-ts 方法是什么?

(items: Item[], keyGetter: (i: Item) => Key) => Record<Key, Item>

到目前为止,我使用自己的非 fp-ts 实现:

function isDefined<T>(value: T): value is Exclude<T, undefined> {
  return value !== undefined;
}

type TIdentifier = string | number;

export const arrayToRecord = <T1, T2 extends TIdentifier = string>(
  arr: T1[],
  getKeyName?: (item: T1) => T2
): Record<T2, T1> => {
  const hasKeyNameGetter = isDefined(getKeyName);
  return arr.reduce((acc, item) => {
    acc[
      hasKeyNameGetter ? (getKeyName as (item: T1) => T2)(item) : ((item as unknown) as T2)
    ] = item;
    return acc;
  }, {} as Record<T2, T1>);
};
4

2 回答 2

2

这是唯一的fp-ts解决方案:

import * as A from "fp-ts/lib/Array";
import * as R from "fp-ts/lib/Record";
import * as semigroup from 'fp-ts/Semigroup';

const arr = A.fromArray([1,2,3]);

const testRecord = R.fromFoldableMap(
  semigroup.last<number>(),
  A.array
)(arr, key => [String(key), key]);
于 2021-09-09T15:06:54.380 回答
1

这是实现您所要求的一种方法。

一些注意事项:

  • 由于字典是在运行时构建的,并且对键没有保证,为了防止不安全的代码,返回类型是Record<string, A>
  • keyGetter不能是可选的,我们必须提供一种方法来想出 e 键
import * as A from 'fp-ts/ReadonlyArray'
import * as R from 'fp-ts/ReadonlyRecord'
import { pipe } from 'fp-ts/function'

const arrayToRecord = <A>(
  items: ReadonlyArray<A>,
  keyGetter: (i: A) => string,
): Readonly<Record<string, A>> =>
  pipe(
    items,
    A.reduce({}, (acc, item) => pipe(acc, R.upsertAt(keyGetter(item), item))),
  )

编辑

根据要求的示例:

const xs = [
  { id: 'abc', date: new Date() },
  { id: 'snt', date: new Date() },
]
const res = arrayToRecord(xs, (x) => x.id)

console.log(res)
// {
//   abc: { id: 'abc', date: 2021-04-06T13:09:25.732Z },
//   snt: { id: 'snt', date: 2021-04-06T13:09:25.732Z }
// }

编辑 2

pipe友好版本:

declare const arrayToRecord: <A>(
  keyGetter: (i: A) => string,
) => (items: ReadonlyArray<A>) => Readonly<Record<string, A>>

interface X { id: string; date: Date }

declare const xs: ReadonlyArray<X>

pipe(
  xs,
  arrayToRecord((x) => x.id),
) // Readonly<Record<string, X>>
于 2021-04-06T12:45:09.737 回答