将数组转换为对象的正确 fp-ts 方法
The proper fp-ts way to convert array into object
我是函数式编程的新手,但想学习最佳实践。
将数组转换为对象的正确 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>);
};
这里有一种方法可以实现您的要求。
一些注意事项:
- 由于字典是在运行时构建的,并且对键没有保证,为了防止不安全的代码,return 类型是
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>>
这是唯一的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]);
我是函数式编程的新手,但想学习最佳实践。
将数组转换为对象的正确 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>);
};
这里有一种方法可以实现您的要求。
一些注意事项:
- 由于字典是在运行时构建的,并且对键没有保证,为了防止不安全的代码,return 类型是
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>>
这是唯一的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]);