@samitouri / QOS-React / commits / a3e576e1bb

Type Transaction (#7581)

This one is interesting because we have transaction objects being passed around everywhere in the codebase but there's actually no Transaction class. It's a "mixin" that comes to life by being Object.assigned to the prototype of a real "class" (before class was cool!). Therefore, we can't just say `var Transaction = require('Transaction'); (transaction: Transaction) => { }` because it would be the object that contains a mixin and not an instance of a transaction. The trick I use is to export `TransactionType` and alias it to `Transaction` in the file as it doesn't actually require transaction. In case they do, we'll figure it out, but in the few files I looked at, it doesn't seem to be the case. For the perform function, it actually typechecks pretty well!

Christopher Chedeau committed Aug 28, 2016 at 16:47 UTC a3e576e1bb80f674fa685966ce415fc65238638c
9 files changed +37 -35
src/renderers/dom/client/ReactReconcileTransaction.js
+1 -1
@@ -175,7 +175,7 @@ var Mixin = {
175 };
176
177
178 -Object.assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
178 +Object.assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
179
180 PooledClass.addPoolingTo(ReactReconcileTransaction);
181
src/renderers/dom/server/ReactServerRenderingTransaction.js
+1 -1
@@ -88,7 +88,7 @@ var Mixin = {
88
89 Object.assign(
90 ReactServerRenderingTransaction.prototype,
91 - Transaction.Mixin,
91 + Transaction,
92 Mixin
93 );
94
src/renderers/dom/server/ReactServerUpdateQueue.js
+4 -2
@@ -13,9 +13,11 @@
13 'use strict';
14
15 var ReactUpdateQueue = require('ReactUpdateQueue');
16 -var Transaction = require('Transaction');
16 +
17 var warning = require('warning');
18
19 +import type { Transaction } from 'Transaction';
20 +
21 function warnNoop(publicInstance: ReactComponent<any, any, any>, callerName: string) {
22 if (__DEV__) {
23 var constructor = publicInstance.constructor;
@@ -39,7 +41,7 @@ function warnNoop(publicInstance: ReactComponent<any, any, any>, callerName: str
41 * @param {Transaction} transaction
42 */
43 class ReactServerUpdateQueue {
42 - /* :: transaction: Transaction; */
44 + transaction: Transaction;
45
46 constructor(transaction: Transaction) {
47 this.transaction = transaction;
src/renderers/native/ReactNativeReconcileTransaction.js
+1 -1
@@ -109,7 +109,7 @@ var Mixin = {
109
110 Object.assign(
111 ReactNativeReconcileTransaction.prototype,
112 - Transaction.Mixin,
112 + Transaction,
113 ReactNativeReconcileTransaction,
114 Mixin
115 );
src/renderers/shared/stack/reconciler/ReactDefaultBatchingStrategy.js
+1 -1
@@ -36,7 +36,7 @@ function ReactDefaultBatchingStrategyTransaction() {
36
37 Object.assign(
38 ReactDefaultBatchingStrategyTransaction.prototype,
39 - Transaction.Mixin,
39 + Transaction,
40 {
41 getTransactionWrappers: function() {
42 return TRANSACTION_WRAPPERS;
src/renderers/shared/stack/reconciler/ReactUpdates.js
+2 -2
@@ -75,7 +75,7 @@ function ReactUpdatesFlushTransaction() {
75
76 Object.assign(
77 ReactUpdatesFlushTransaction.prototype,
78 - Transaction.Mixin,
78 + Transaction,
79 {
80 getTransactionWrappers: function() {
81 return TRANSACTION_WRAPPERS;
@@ -92,7 +92,7 @@ Object.assign(
92 perform: function(method, scope, a) {
93 // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
94 // with this transaction's wrappers around it.
95 - return Transaction.Mixin.perform.call(
95 + return Transaction.perform.call(
96 this,
97 this.reconcileTransaction.perform,
98 this.reconcileTransaction,
src/renderers/shared/utils/Transaction.js
+20 -20
@@ -7,12 +7,15 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule Transaction
10 + * @flow
11 */
12
13 'use strict';
14
15 var invariant = require('invariant');
16
17 +var OBSERVED_ERROR = {};
18 +
19 /**
20 * `Transaction` creates a black box that is able to wrap any method such that
21 * certain invariants are maintained before and after the method is invoked
@@ -74,7 +77,7 @@ var invariant = require('invariant');
77 *
78 * @class Transaction
79 */
77 -var Mixin = {
80 +var TransactionImpl = {
81 /**
82 * Sets up this instance so that it is prepared for collecting metrics. Does
83 * so such that this setup method may be used on an instance that is already
@@ -82,7 +85,7 @@ var Mixin = {
85 * That can be useful if you decide to make your subclass of this mixin a
86 * "PooledClass".
87 */
85 - reinitializeTransaction: function() {
88 + reinitializeTransaction: function(): void {
89 this.transactionWrappers = this.getTransactionWrappers();
90 if (this.wrapperInitData) {
91 this.wrapperInitData.length = 0;
@@ -100,7 +103,7 @@ var Mixin = {
103 */
104 getTransactionWrappers: null,
105
103 - isInTransaction: function() {
106 + isInTransaction: function(): bool {
107 return !!this._isInTransaction;
108 },
109
@@ -121,7 +124,13 @@ var Mixin = {
124 *
125 * @return {*} Return value from `method`.
126 */
124 - perform: function(method, scope, a, b, c, d, e, f) {
127 + perform: function<
128 + A, B, C, D, E, F, G,
129 + T: (a: A, b: B, c: C, d: D, e: E, f: F) => G // eslint-disable-line space-before-function-paren
130 + >(
131 + method: T, scope: any,
132 + a: A, b: B, c: C, d: D, e: E, f: F,
133 + ): G {
134 invariant(
135 !this.isInTransaction(),
136 'Transaction.perform(...): Cannot initialize a transaction when there ' +
@@ -160,7 +169,7 @@ var Mixin = {
169 return ret;
170 },
171
163 - initializeAll: function(startIndex) {
172 + initializeAll: function(startIndex: number): void {
173 var transactionWrappers = this.transactionWrappers;
174 for (var i = startIndex; i < transactionWrappers.length; i++) {
175 var wrapper = transactionWrappers[i];
@@ -169,12 +178,12 @@ var Mixin = {
178 // OBSERVED_ERROR state before overwriting it with the real return value
179 // of initialize -- if it's still set to OBSERVED_ERROR in the finally
180 // block, it means wrapper.initialize threw.
172 - this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
181 + this.wrapperInitData[i] = OBSERVED_ERROR;
182 this.wrapperInitData[i] = wrapper.initialize ?
183 wrapper.initialize.call(this) :
184 null;
185 } finally {
177 - if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
186 + if (this.wrapperInitData[i] === OBSERVED_ERROR) {
187 // The initializer for wrapper i threw an error; initialize the
188 // remaining wrappers but silence any exceptions from them to ensure
189 // that the first error is the one to bubble up.
@@ -193,7 +202,7 @@ var Mixin = {
202 * (`close`rs that correspond to initializers that failed will not be
203 * invoked).
204 */
196 - closeAll: function(startIndex) {
205 + closeAll: function(startIndex: number): void {
206 invariant(
207 this.isInTransaction(),
208 'Transaction.closeAll(): Cannot close transaction when none are open.'
@@ -209,7 +218,7 @@ var Mixin = {
218 // close -- if it's still set to true in the finally block, it means
219 // wrapper.close threw.
220 errorThrown = true;
212 - if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) {
221 + if (initData !== OBSERVED_ERROR && wrapper.close) {
222 wrapper.close.call(this, initData);
223 }
224 errorThrown = false;
@@ -229,15 +238,6 @@ var Mixin = {
238 },
239 };
240
232 -var Transaction = {
233 -
234 - Mixin: Mixin,
235 -
236 - /**
237 - * Token to look for to determine if an error occurred.
238 - */
239 - OBSERVED_ERROR: {},
240 -
241 -};
241 +export type Transaction = typeof TransactionImpl;
242
243 -module.exports = Transaction;
243 +module.exports = TransactionImpl;
src/renderers/shared/utils/__tests__/Transaction-test.js
+6 -6
@@ -45,7 +45,7 @@ describe('Transaction', function() {
45 this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
46 this.lastCloseParam = INIT_ERRORED; // WON'T be set to something else
47 };
48 - Object.assign(TestTransaction.prototype, Transaction.Mixin);
48 + Object.assign(TestTransaction.prototype, Transaction);
49 TestTransaction.prototype.getTransactionWrappers = function() {
50 return [
51 {
@@ -96,7 +96,7 @@ describe('Transaction', function() {
96 this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
97 this.lastCloseParam = INIT_ERRORED; // WILL be set to something else
98 };
99 - Object.assign(TestTransaction.prototype, Transaction.Mixin);
99 + Object.assign(TestTransaction.prototype, Transaction);
100 TestTransaction.prototype.getTransactionWrappers = function() {
101 return [
102 {
@@ -157,7 +157,7 @@ describe('Transaction', function() {
157 this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
158 this.lastCloseParam = INIT_ERRORED; // WILL be set to something else
159 };
160 - Object.assign(TestTransaction.prototype, Transaction.Mixin);
160 + Object.assign(TestTransaction.prototype, Transaction);
161 // Now, none of the close/inits throw, but the operation we wrap will throw.
162 TestTransaction.prototype.getTransactionWrappers = function() {
163 return [
@@ -221,7 +221,7 @@ describe('Transaction', function() {
221 var TestTransaction = function() {
222 this.reinitializeTransaction();
223 };
224 - Object.assign(TestTransaction.prototype, Transaction.Mixin);
224 + Object.assign(TestTransaction.prototype, Transaction);
225 var exceptionMsg = 'This exception should throw.';
226 TestTransaction.prototype.getTransactionWrappers = function() {
227 return [
@@ -250,7 +250,7 @@ describe('Transaction', function() {
250 this.reinitializeTransaction();
251 this.firstCloseParam = INIT_ERRORED; // WILL be set to something else
252 };
253 - Object.assign(TestTransaction.prototype, Transaction.Mixin);
253 + Object.assign(TestTransaction.prototype, Transaction);
254 TestTransaction.prototype.getTransactionWrappers = function() {
255 return [
256 {
@@ -278,7 +278,7 @@ describe('Transaction', function() {
278 var NestedTransaction = function() {
279 this.reinitializeTransaction();
280 };
281 - Object.assign(NestedTransaction.prototype, Transaction.Mixin);
281 + Object.assign(NestedTransaction.prototype, Transaction);
282 NestedTransaction.prototype.getTransactionWrappers = function() {
283 return [
284 {
src/renderers/testing/ReactTestReconcileTransaction.js
+1 -1
@@ -114,7 +114,7 @@ var Mixin = {
114
115 Object.assign(
116 ReactTestReconcileTransaction.prototype,
117 - Transaction.Mixin,
117 + Transaction,
118 ReactTestReconcileTransaction,
119 Mixin
120 );