-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathobject-map.js
49 lines (48 loc) · 2.16 KB
/
object-map.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const { entries, fromEntries } = Object;
/**
* By analogy with how `Array.prototype.map` will map the elements of
* an array to transformed elements of an array of the same shape,
* `objectMap` will do likewise for the string-named own enumerable
* properties of an object.
*
* Typical usage applies `objectMap` to a CopyRecord, i.e.,
* an object for which `passStyleOf(original) === 'copyRecord'`. For these,
* none of the following edge cases arise. The result will be a CopyRecord
* with exactly the same property names, whose values are the mapped form of
* the original's values.
*
* When the original is not a CopyRecord, some edge cases to be aware of
* * No matter how mutable the original object, the returned object is
* hardened.
* * Only the string-named enumerable own properties of the original
* are mapped. All other properties are ignored.
* * If any of the original properties were accessors, `Object.entries`
* will cause its `getter` to be called and will use the resulting
* value.
* * No matter whether the original property was an accessor, writable,
* or configurable, all the properties of the returned object will be
* non-writable, non-configurable, data properties.
* * No matter what the original object may have inherited from, and
* no matter whether it was a special kind of object such as an array,
* the returned object will always be a plain object inheriting directly
* from `Object.prototype` and whose state is only these new mapped
* own properties.
*
* With these differences, even if the original object was not a CopyRecord,
* if all the mapped values are Passable, then the returned object will be
* a CopyRecord.
*
* @template {Record<string, any>} O
* @template R map result
* @param {O} original
* @param {(value: O[keyof O], key: keyof O) => R} mapFn
* @returns {Record<keyof O, R>}
*/
export const objectMap = (original, mapFn) => {
const ents = entries(original);
const mapEnts = ents.map(
([k, v]) => /** @type {[keyof O, R]} */ ([k, mapFn(v, k)]),
);
return /** @type {Record<keyof O, R>} */ (harden(fromEntries(mapEnts)));
};
harden(objectMap);