Skip to content

Commit 31a6fad

Browse files
committed
Add objectFromEntries(), objectMap()
1 parent f3519aa commit 31a6fad

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/objectFromEntries.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Type-safe version of Object.fromEntries(). Like the latter, it creates an
3+
* object from the provided list of key-value pairs.
4+
*/
5+
export const objectFromEntries = <
6+
const KVPairs extends ReadonlyArray<readonly [PropertyKey, unknown]>,
7+
>(
8+
keyValuePairs: KVPairs
9+
): { [K in KVPairs[number] as K[0]]: K[1] } => {
10+
return Object.fromEntries(keyValuePairs) as { [K in KVPairs[number] as K[0]]: K[1] };
11+
};

src/objectMap.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { objectFromEntries } from "./objectFromEntries";
2+
3+
/**
4+
* Union type representing the type of an arbitrary key-value pair in a given
5+
* object type.
6+
*/
7+
type KeyValueType<TObj> = {
8+
[K in keyof TObj]: { key: K; value: TObj[K] };
9+
}[keyof TObj];
10+
11+
/**
12+
* Like Array.prototype.map() but for objects, i.e. applies `mapper` to every
13+
* key-value pair and builds a new object from the returned values.
14+
*
15+
* @param obj Object to be mapped
16+
* @param keys The keys that should be mapped. We need a precise list, because
17+
* functions like Object.keys(obj) or Object.entries(keys) might return
18+
* additional keys not included in TObject/TKey.
19+
* @param mapper Callback function which maps each (key, value) pair to a new
20+
* value.
21+
* @returns An object with the same keys as `obj` but with the values given by
22+
* `mapper()`. The return type should be equivalent to `{ [K in TKey]: TNewValue }`
23+
* but for some reason TSC doesn't think so. (Bug?)
24+
*/
25+
export const objectMap = <TObj extends unknown, TKey extends keyof TObj, TNewValue extends unknown>(
26+
obj: Readonly<TObj>,
27+
keys: TKey[],
28+
mapper: (keyValuePair: KeyValueType<Pick<TObj, TKey>>) => TNewValue
29+
): { [K in readonly [TKey, TNewValue] as K[0]]: K[1] } => {
30+
const keyValuePairs = keys.map((key) => [key, mapper({ key, value: obj[key] })] as const);
31+
return objectFromEntries(keyValuePairs);
32+
};

0 commit comments

Comments
 (0)