Update Flow to 0.273 (#34274)
This version introduces "Natural Inference" which requires a couple more type annotations to make Flow pass.
Jan Kassens committed
Aug 22, 2025 at 16:58 UTC
4049cfeeab33146e02b0721477fd5f2020f76a04
15 files changed
+40
-34
.eslintrc.js
+1
@@ -565,6 +565,7 @@ module.exports = {
565
BigInt: 'readonly',
566
BigInt64Array: 'readonly',
567
BigUint64Array: 'readonly',
568
+ CacheType: 'readonly',
569
Class: 'readonly',
570
ClientRect: 'readonly',
571
CopyInspectedElementPath: 'readonly',
package.json
+2
-2
@@ -74,8 +74,8 @@
74
"eslint-plugin-react-internal": "link:./scripts/eslint-rules",
75
"fbjs-scripts": "^3.0.1",
76
"filesize": "^6.0.1",
77
- "flow-bin": "^0.272",
78
- "flow-remove-types": "^2.272",
77
+ "flow-bin": "^0.273",
78
+ "flow-remove-types": "^2.273",
79
"flow-typed": "^4.1.1",
80
"glob": "^7.1.6",
81
"glob-stream": "^6.1.0",
packages/react-devtools-shared/src/backend/fiber/renderer.js
+1
-1
@@ -6705,7 +6705,7 @@ export function attach(
6705
if (isMostRecentlyInspectedElement(id) && !forceFullData) {
6706
if (!hasElementUpdatedSinceLastInspected) {
6707
if (path !== null) {
6708
- let secondaryCategory = null;
6708
+ let secondaryCategory: 'suspendedBy' | 'hooks' | null = null;
6709
if (path[0] === 'hooks') {
6710
secondaryCategory = 'hooks';
6711
}
packages/react-devtools-shared/src/hookNamesCache.js
+1
-1
@@ -103,7 +103,7 @@ export function loadHookNames(
103
104
let timeoutID: $FlowFixMe | null;
105
let didTimeout = false;
106
- let status = 'unknown';
106
+ let status: 'success' | 'error' | 'timeout' | 'unknown' = 'unknown';
107
let resolvedHookNames: HookNames | null = null;
108
109
const wake = () => {
packages/react-devtools-shared/src/hooks/parseHookNames/loadSourceAndMetadata.js
+1
-1
@@ -64,7 +64,7 @@ import type {FetchFileWithCaching} from 'react-devtools-shared/src/devtools/view
64
65
// Prefer a cached albeit stale response to reduce download time.
66
// We wouldn't want to load/parse a newer version of the source (even if one existed).
67
-const FETCH_OPTIONS = {cache: 'force-cache'};
67
+const FETCH_OPTIONS = {cache: 'force-cache' as CacheType};
68
69
const MAX_SOURCE_LENGTH = 100_000_000;
70
packages/react-devtools-timeline/src/import-worker/preprocessData.js
+3
-3
@@ -509,7 +509,7 @@ function processTimelineEvent(
509
} else if (name.startsWith('--schedule-forced-update-')) {
510
const [laneBitmaskString, componentName] = name.slice(25).split('-');
511
512
- const forceUpdateEvent = {
512
+ const forceUpdateEvent: SchedulingEvent = {
513
type: 'schedule-force-update',
514
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
515
componentName,
@@ -527,7 +527,7 @@ function processTimelineEvent(
527
} else if (name.startsWith('--schedule-state-update-')) {
528
const [laneBitmaskString, componentName] = name.slice(24).split('-');
529
530
- const stateUpdateEvent = {
530
+ const stateUpdateEvent: SchedulingEvent = {
531
type: 'schedule-state-update',
532
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
533
componentName,
@@ -578,7 +578,7 @@ function processTimelineEvent(
578
// We can't know if they'll be resolved or not at this point.
579
// We'll just give them a default (fake) duration width.
580
581
- const suspenseEvent = {
581
+ const suspenseEvent: SuspenseEvent = {
582
componentName,
583
depth,
584
duration: null,
packages/react-dom-bindings/src/client/inputValueTracking.js
+6
-3
@@ -140,7 +140,7 @@ export function trackHydrated(
140
return false;
141
}
142
143
- let valueField;
143
+ let valueField: 'checked' | 'value';
144
let expectedValue;
145
if (isCheckable(node)) {
146
valueField = 'checked';
@@ -150,8 +150,11 @@ export function trackHydrated(
150
valueField = 'value';
151
expectedValue = initialValue;
152
}
153
- // eslint-disable-next-line react-internal/safe-string-coercion
154
- const currentValue = '' + (node[valueField]: any);
153
+ const currentValue =
154
+ // eslint-disable-next-line react-internal/safe-string-coercion
155
+ '' +
156
+ (// $FlowFixMe[prop-missing]
157
+ node[valueField]: any);
158
node._valueTracker = trackValueOnNode(node, valueField, expectedValue);
159
return currentValue !== expectedValue;
160
}
packages/react-dom-bindings/src/events/SyntheticEvent.js
+7
-7
@@ -146,7 +146,7 @@ function createSyntheticEvent(Interface: EventInterfaceType) {
146
* @interface Event
147
* @see http://www.w3.org/TR/DOM-Level-3-Events/
148
*/
149
-const EventInterface = {
149
+const EventInterface: EventInterfaceType = {
150
eventPhase: 0,
151
bubbles: 0,
152
cancelable: 0,
@@ -442,7 +442,7 @@ function getEventModifierState(nativeEvent: {[propName: string]: mixed}) {
442
* @interface KeyboardEvent
443
* @see http://www.w3.org/TR/DOM-Level-3-Events/
444
*/
445
-const KeyboardEventInterface = {
445
+const KeyboardEventInterface: EventInterfaceType = {
446
...UIEventInterface,
447
key: getEventKey,
448
code: 0,
@@ -505,7 +505,7 @@ export const SyntheticKeyboardEvent: $FlowFixMe = createSyntheticEvent(
505
* @interface PointerEvent
506
* @see http://www.w3.org/TR/pointerevents/
507
*/
508
-const PointerEventInterface = {
508
+const PointerEventInterface: EventInterfaceType = {
509
...MouseEventInterface,
510
pointerId: 0,
511
width: 0,
@@ -526,7 +526,7 @@ export const SyntheticPointerEvent: $FlowFixMe = createSyntheticEvent(
526
* @interface TouchEvent
527
* @see http://www.w3.org/TR/touch-events/
528
*/
529
-const TouchEventInterface = {
529
+const TouchEventInterface: EventInterfaceType = {
530
...UIEventInterface,
531
touches: 0,
532
targetTouches: 0,
@@ -545,7 +545,7 @@ export const SyntheticTouchEvent: $FlowFixMe =
545
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
546
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
547
*/
548
-const TransitionEventInterface = {
548
+const TransitionEventInterface: EventInterfaceType = {
549
...EventInterface,
550
propertyName: 0,
551
elapsedTime: 0,
@@ -559,7 +559,7 @@ export const SyntheticTransitionEvent: $FlowFixMe = createSyntheticEvent(
559
* @interface WheelEvent
560
* @see http://www.w3.org/TR/DOM-Level-3-Events/
561
*/
562
-const WheelEventInterface = {
562
+const WheelEventInterface: EventInterfaceType = {
563
...MouseEventInterface,
564
deltaX(event: {[propName: string]: mixed}) {
565
return 'deltaX' in event
@@ -594,7 +594,7 @@ const WheelEventInterface = {
594
export const SyntheticWheelEvent: $FlowFixMe =
595
createSyntheticEvent(WheelEventInterface);
596
597
-const ToggleEventInterface = {
597
+const ToggleEventInterface: EventInterfaceType = {
598
...EventInterface,
599
newState: 0,
600
oldState: 0,
packages/react-dom-bindings/src/shared/ReactDOMFormActions.js
+1
-1
@@ -31,7 +31,7 @@ export type FormStatus = FormStatusPending | FormStatusNotPending;
31
32
// Since the "not pending" value is always the same, we can reuse the
33
// same object across all transitions.
34
-const sharedNotPendingObject = {
34
+const sharedNotPendingObject: FormStatusNotPending = {
35
pending: false,
36
data: null,
37
method: null,
packages/react-native-renderer/src/legacy-events/ResponderTouchHistoryStore.js
+1
@@ -207,6 +207,7 @@ const ResponderTouchHistoryStore = {
207
touchHistory.numberActiveTouches = nativeEvent.touches.length;
208
if (touchHistory.numberActiveTouches === 1) {
209
touchHistory.indexOfSingleActiveTouch =
210
+ // $FlowFixMe[incompatible-type] might be null according to type
211
nativeEvent.touches[0].identifier;
212
}
213
} else if (isEndish(topLevelType)) {
packages/react-reconciler/src/ReactFiberCommitWork.js
+2
-2
@@ -5020,7 +5020,7 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
5020
const instance: OffscreenInstance = offscreenFiber.stateNode;
5021
const transitions = instance._transitions;
5022
if (transitions !== null) {
5023
- const abortReason = {
5023
+ const abortReason: TransitionAbort = {
5024
reason: 'suspense',
5025
name: current.memoizedProps.name || null,
5026
};
@@ -5061,7 +5061,7 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
5061
const instance: TracingMarkerInstance = current.stateNode;
5062
const transitions = instance.transitions;
5063
if (transitions !== null) {
5064
- const abortReason = {
5064
+ const abortReason: TransitionAbort = {
5065
reason: 'marker',
5066
name: current.memoizedProps.name,
5067
};
packages/react-test-renderer/src/ReactTestRenderer.js
+2
-1
@@ -9,6 +9,7 @@
9
10
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
11
import type {
12
+ Container,
13
PublicInstance,
14
Instance,
15
TextInstance,
@@ -505,7 +506,7 @@ function create(
506
isStrictMode = true;
507
}
508
}
508
- let container = {
509
+ let container: Container = {
510
children: ([]: Array<Instance | TextInstance>),
511
createNodeMock,
512
tag: 'CONTAINER',
packages/scheduler/src/forks/SchedulerPostTask.js
+1
-1
@@ -76,7 +76,7 @@ export function unstable_scheduleCallback<T>(
76
callback: SchedulerCallback<T>,
77
options?: {delay?: number},
78
): CallbackNode {
79
- let postTaskPriority;
79
+ let postTaskPriority: PostTaskPriorityLevel;
80
switch (priorityLevel) {
81
case ImmediatePriority:
82
case UserBlockingPriority:
packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js
+6
-6
@@ -23,8 +23,7 @@ export function useSyncExternalStoreWithSelector<Snapshot, Selection>(
23
selector: (snapshot: Snapshot) => Selection,
24
isEqual?: (a: Selection, b: Selection) => boolean,
25
): Selection {
26
- // Use this to track the rendered snapshot.
27
- const instRef = useRef<
26
+ type Inst =
27
| {
28
hasValue: true,
29
value: Selection,
@@ -32,10 +31,11 @@ export function useSyncExternalStoreWithSelector<Snapshot, Selection>(
31
| {
32
hasValue: false,
33
value: null,
35
- }
36
- | null,
37
- >(null);
38
- let inst;
34
+ };
35
+
36
+ // Use this to track the rendered snapshot.
37
+ const instRef = useRef<Inst | null>(null);
38
+ let inst: Inst;
39
if (instRef.current === null) {
40
inst = {
41
hasValue: false,
yarn.lock
+5
-5
@@ -9298,12 +9298,12 @@ flatted@^3.2.9:
9298
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
9299
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
9300
9301
-flow-bin@^0.272:
9302
- version "0.272.2"
9303
- resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.272.2.tgz#918fc58dc7a99725a83314f453d3e49a56aebdc5"
9304
- integrity sha512-Rf8UG1biRBUGGh6qN7Ua2Y2lJRpR8Pbzby5kfHQ5m5SgjC5eOPw3Qjbrheb9ec5oU4L1gCOXRYbkbpr02PRUBw==
9301
+flow-bin@^0.273:
9302
+ version "0.273.1"
9303
+ resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.273.1.tgz#18621f169ecbabe3656c56980ebaabc439ee76c1"
9304
+ integrity sha512-OlJkNCSd+i6z5xDoyGiS+3X5xYQx+vVUY2iUw6cHJR0LK3ttyA1wkiI93OuBALhLhF91KayzGhRSzXHqA75iUw==
9305
9306
-flow-remove-types@^2.272:
9306
+flow-remove-types@^2.273:
9307
version "2.279.0"
9308
resolved "https://registry.yarnpkg.com/flow-remove-types/-/flow-remove-types-2.279.0.tgz#3a3388d9158eba0f82c40d80d31d9640b883a3f5"
9309
integrity sha512-bPFloMR/A2b/r/sIsf7Ix0LaMicCJNjwhXc4xEEQVzJCIz5u7C7XDaEOXOiqveKlCYK7DcBNn6R01Cbbc9gsYA==