The library for web and native user interfaces.
Typecheck ImmutableObject
Just some therapeutic cleanup.
Tim Yung committed
Jul 24, 2013 at 17:19 UTC
8d48610b7e6a9d31a5ea9044b180c73053d066b7
1 file changed
+72
-69
src/utils/ImmutableObject.js
+72
-69
@@ -14,112 +14,111 @@
14
* limitations under the License.
15
*
16
* @providesModule ImmutableObject
17
+ * @typechecks
18
*/
19
20
"use strict";
21
21
-var keyMirror = require('keyMirror');
22
+var invariant = require('invariant');
23
var merge = require('merge');
24
var mergeInto = require('mergeInto');
25
var mergeHelpers = require('mergeHelpers');
25
-var throwIf = require('throwIf');
26
27
var checkMergeObjectArgs = mergeHelpers.checkMergeObjectArgs;
28
var isTerminal = mergeHelpers.isTerminal;
29
30
/**
31
- * Simple wrapper around javascript key/value objects that provide a dev time
32
- * guarantee of immutability (assuming all modules that may potentially mutate
33
- * include a "use strict" declaration). Retaining immutability requires CPU
34
- * cycles (in order to perform the freeze), but this computation can be avoided
35
- * in production. The fact that mutation attempts in __DEV__ will be caught,
36
- * allows us to reasonably assume that mutation on those objects won't even be
37
- * attempted in production. This means that an object being an instanceof
38
- * `ImmutableObject` implies that the object may never change.
39
- *
40
- * TODO: Require strict mode in source files that use ImmutableObject (lint
41
- * rule).
42
- *
43
- * @class ImmutableObject
31
+ * Wrapper around JavaScript objects that provide a guarantee of immutability at
32
+ * developer time when strict mode is used. The extra computations required to
33
+ * enforce immutability is stripped out in production for performance reasons.
34
*/
45
-
46
-var ERRORS;
35
var ImmutableObject;
36
49
-if (__DEV__) {
50
- ERRORS = {
51
- INVALID_MAP_SET_ARG: 'You have attempted to set fields on an object that ' +
52
- 'is not an instance of ImmutableObject'
53
- };
37
+function assertImmutableObject(immutableObject) {
38
+ invariant(
39
+ immutableObject instanceof ImmutableObject,
40
+ 'ImmutableObject: Attempted to set fields on an object that is not an ' +
41
+ 'instance of ImmutableObject.'
42
+ );
43
+}
44
45
+if (__DEV__) {
46
/**
47
* Constructs an instance of `ImmutableObject`.
48
*
58
- * @param {!Object} initMap The initial set of properties.
49
+ * @param {?object} initialProperties The initial set of properties.
50
* @constructor
51
*/
61
- ImmutableObject = function(initMap) {
62
- mergeInto(this, initMap);
63
- deepFreeze(this, initMap);
52
+ ImmutableObject = function ImmutableObject(initialProperties) {
53
+ mergeInto(this, initialProperties);
54
+ deepFreeze(this);
55
};
56
57
/**
67
- * Objects that are instances of `ImmutableObject` are assumed to be deep
68
- * frozen.
69
- * @param {!Object} o The object to deep freeze.
70
- * @return {!boolean} Whether or not deep freeze is needed.
58
+ * Checks if an object should be deep frozen. Instances of `ImmutableObject`
59
+ * are assumed to have already been deep frozen.
60
+ *
61
+ * @param {*} object The object to check.
62
+ * @return {boolean} Whether or not deep freeze is needed.
63
*/
72
- var shouldRecurseFreeze = function(o) {
73
- return (typeof o) === 'object' &&
74
- !(o instanceof ImmutableObject) && o !== null;
64
+ var shouldRecurseFreeze = function(object) {
65
+ return (
66
+ typeof object === 'object' &&
67
+ !(object instanceof ImmutableObject) &&
68
+ object !== null
69
+ );
70
};
71
72
/**
78
- * Freezes an object `o` deeply. Invokes `shouldRecurseFreeze` to determine if
79
- * further freezing is needed.
73
+ * Freezes the supplied object deeply.
74
*
81
- * @param {!Object} o The object to freeze.
75
+ * @param {*} object The object to freeze.
76
*/
83
- var deepFreeze = function(o) {
84
- var prop;
85
- Object.freeze(o); // First freeze the object.
86
- for (prop in o) {
87
- var field = o[prop];
88
- if (o.hasOwnProperty(prop) && shouldRecurseFreeze(field)) {
77
+ var deepFreeze = function(object) {
78
+ Object.freeze(object); // First freeze the object.
79
+ for (var prop in object) {
80
+ var field = object[prop];
81
+ if (object.hasOwnProperty(prop) && shouldRecurseFreeze(field)) {
82
deepFreeze(field);
83
}
84
}
85
};
86
87
/**
95
- * Returns a new ImmutableObject that is that is the same as the parameter
96
- * `immutableObject` but with the differences specified in `put`.
97
- * @param {!ImmutableObject} ImmutableObject The ImmutableObject object to set
98
- * fields on.
99
- * @param {!Object} put Subset of fields to merge into the returned result.
100
- * @return {!ImmutableObject} The result of merging in `put` fields.
88
+ * Returns a new ImmutableObject that is identical to the supplied object but
89
+ * with the supplied changes, `put`.
90
+ *
91
+ * @param {ImmutableObject} immutableObject Starting object.
92
+ * @param {?object} put Fields to merge into the object.
93
+ * @return {ImmutableObject} The result of merging in `put` fields.
94
*/
95
ImmutableObject.set = function(immutableObject, put) {
103
- throwIf(
104
- !(immutableObject instanceof ImmutableObject),
105
- ERRORS.INVALID_MAP_SET_ARG
106
- );
96
+ assertImmutableObject(immutableObject);
97
var totalNewFields = merge(immutableObject, put);
98
return new ImmutableObject(totalNewFields);
99
};
100
101
} else {
112
- ERRORS = keyMirror({INVALID_MAP_SET_ARG: null});
113
-
114
- ImmutableObject = function(initMap) {
115
- mergeInto(this, initMap);
102
+ /**
103
+ * Constructs an instance of `ImmutableObject`.
104
+ *
105
+ * @param {?object} initialProperties The initial set of properties.
106
+ * @constructor
107
+ */
108
+ ImmutableObject = function ImmutableObject(initialProperties) {
109
+ mergeInto(this, initialProperties);
110
};
111
112
+ /**
113
+ * Returns a new ImmutableObject that is identical to the supplied object but
114
+ * with the supplied changes, `put`.
115
+ *
116
+ * @param {ImmutableObject} immutableObject Starting object.
117
+ * @param {?object} put Fields to merge into the object.
118
+ * @return {ImmutableObject} The result of merging in `put` fields.
119
+ */
120
ImmutableObject.set = function(immutableObject, put) {
119
- throwIf(
120
- !(immutableObject instanceof ImmutableObject),
121
- ERRORS.INVALID_MAP_SET_ARG
122
- );
121
+ assertImmutableObject(immutableObject);
122
var newMap = new ImmutableObject(immutableObject);
123
mergeInto(newMap, put);
124
return newMap;
@@ -127,8 +126,12 @@ if (__DEV__) {
126
}
127
128
/**
130
- * Sugar for `ImmutableObject.set(ImmutableObject, {fieldName: putField})`
131
- * @see ImmutableObject.set
129
+ * Sugar for `ImmutableObject.set(ImmutableObject, {fieldName: putField})`.
130
+ *
131
+ * @param {ImmutableObject} immutableObject Object on which to set field.
132
+ * @param {string} fieldName Name of the field to set.
133
+ * @param {*} putField Value of the field to set.
134
+ * @return {ImmutableObject} [description]
135
*/
136
ImmutableObject.setField = function(immutableObject, fieldName, putField) {
137
var put = {};
@@ -137,15 +140,15 @@ ImmutableObject.setField = function(immutableObject, fieldName, putField) {
140
};
141
142
/**
140
- * Returns a new ImmutableObject that is that is the same as the parameter
141
- * `immutableObject` but with the differences specified in `put` recursively
142
- * applied.
143
+ * Returns a new ImmutableObject that is identical to the supplied object but
144
+ * with the supplied changes recursively applied.
145
+ *
146
+ * @param {ImmutableObject} immutableObject Object on which to set fields.
147
+ * @param {object} put Fields to merge into the object.
148
+ * @return {ImmutableObject} The result of merging in `put` fields.
149
*/
150
ImmutableObject.setDeep = function(immutableObject, put) {
145
- throwIf(
146
- !(immutableObject instanceof ImmutableObject),
147
- ERRORS.INVALID_MAP_SET_ARG
148
- );
151
+ assertImmutableObject(immutableObject);
152
return _setDeep(immutableObject, put);
153
};
154