Move Built-in Props Types to React Types (#32841)
Stacked on #32838. We don't always type the Props of built-ins. This adds typing for most of the built-ins. When we did type them, we used to put it in the `ReactFiber...Component` files but any public API like this can be implemented in other renderers too such as Fizz. So I moved them to `shared/ReactTypes` which is where we put other public API types (that are not already built-in to Flow). That way Fizz can import them and assert properly when it accesses the props.
Sebastian Markbåge committed
Apr 9, 2025 at 22:44 UTC
c44e4a250557e53b120e40db8b01fb5fd93f1e35
13 files changed
+132
-103
packages/react-reconciler/src/ReactFiber.js
+8
-6
@@ -8,23 +8,25 @@
8
*/
9
10
import type {ReactElement} from 'shared/ReactElementType';
11
-import type {ReactFragment, ReactPortal, ReactScope} from 'shared/ReactTypes';
11
+import type {
12
+ ReactFragment,
13
+ ReactPortal,
14
+ ReactScope,
15
+ ViewTransitionProps,
16
+ ActivityProps,
17
+} from 'shared/ReactTypes';
18
import type {Fiber} from './ReactInternalTypes';
19
import type {RootTag} from './ReactRootTags';
20
import type {WorkTag} from './ReactWorkTags';
21
import type {TypeOfMode} from './ReactTypeOfMode';
22
import type {Lanes} from './ReactFiberLane';
23
import type {SuspenseInstance} from './ReactFiberConfig';
18
-import type {ActivityProps} from './ReactFiberActivityComponent';
24
import type {
25
LegacyHiddenProps,
26
OffscreenProps,
27
OffscreenInstance,
28
} from './ReactFiberOffscreenComponent';
24
-import type {
25
- ViewTransitionProps,
26
- ViewTransitionState,
27
-} from './ReactFiberViewTransitionComponent';
29
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
30
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
31
32
import {
packages/react-reconciler/src/ReactFiberActivityComponent.js
deleted
-15
@@ -1,15 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-import type {ReactNodeList} from 'shared/ReactTypes';
11
-
12
-export type ActivityProps = {
13
- mode?: 'hidden' | 'visible' | null | void,
14
- children?: ReactNodeList,
15
-};
packages/react-reconciler/src/ReactFiberApplyGesture.js
+3
-4
@@ -7,16 +7,15 @@
7
* @flow
8
*/
9
10
+import type {ViewTransitionProps} from 'shared/ReactTypes';
11
+
12
import type {Fiber, FiberRoot} from './ReactInternalTypes';
13
14
import type {Instance, TextInstance, Props} from './ReactFiberConfig';
15
16
import type {OffscreenState} from './ReactFiberOffscreenComponent';
17
16
-import type {
17
- ViewTransitionState,
18
- ViewTransitionProps,
19
-} from './ReactFiberViewTransitionComponent';
18
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
19
20
import {
21
cloneMutableInstance,
packages/react-reconciler/src/ReactFiberBeginWork.js
+18
-12
@@ -11,6 +11,12 @@ import type {
11
ReactConsumerType,
12
ReactContext,
13
ReactNodeList,
14
+ ViewTransitionProps,
15
+ ActivityProps,
16
+ SuspenseProps,
17
+ TracingMarkerProps,
18
+ CacheProps,
19
+ ProfilerProps,
20
} from 'shared/ReactTypes';
21
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
22
import type {Fiber, FiberRoot} from './ReactInternalTypes';
@@ -22,7 +28,6 @@ import type {
28
SuspenseListTailMode,
29
} from './ReactFiberSuspenseComponent';
30
import type {SuspenseContext} from './ReactFiberSuspenseContext';
25
-import type {ActivityProps} from './ReactFiberActivityComponent';
31
import type {
32
LegacyHiddenProps,
33
OffscreenProps,
@@ -30,10 +35,7 @@ import type {
35
OffscreenQueue,
36
OffscreenInstance,
37
} from './ReactFiberOffscreenComponent';
33
-import type {
34
- ViewTransitionProps,
35
- ViewTransitionState,
36
-} from './ReactFiberViewTransitionComponent';
38
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
39
import {assignViewTransitionAutoName} from './ReactFiberViewTransitionComponent';
40
import type {
41
Cache,
@@ -977,7 +979,9 @@ function updateCacheComponent(
979
}
980
}
981
980
- const nextChildren = workInProgress.pendingProps.children;
982
+ const nextProps: CacheProps = workInProgress.pendingProps;
983
+
984
+ const nextChildren = nextProps.children;
985
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
986
return workInProgress.child;
987
}
@@ -992,6 +996,8 @@ function updateTracingMarkerComponent(
996
return null;
997
}
998
999
+ const nextProps: TracingMarkerProps = workInProgress.pendingProps;
1000
+
1001
// TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed.
1002
// A tracing marker is only associated with the transitions that rendered
1003
// or updated it, so we can create a new set of transitions each time
@@ -1002,7 +1008,7 @@ function updateTracingMarkerComponent(
1008
tag: TransitionTracingMarker,
1009
transitions: new Set(currentTransitions),
1010
pendingBoundaries: null,
1005
- name: workInProgress.pendingProps.name,
1011
+ name: nextProps.name,
1012
aborts: null,
1013
};
1014
workInProgress.stateNode = markerInstance;
@@ -1015,7 +1021,7 @@ function updateTracingMarkerComponent(
1021
}
1022
} else {
1023
if (__DEV__) {
1018
- if (current.memoizedProps.name !== workInProgress.pendingProps.name) {
1024
+ if (current.memoizedProps.name !== nextProps.name) {
1025
console.error(
1026
'Changing the name of a tracing marker after mount is not supported. ' +
1027
'To remount the tracing marker, pass it a new key.',
@@ -1028,7 +1034,7 @@ function updateTracingMarkerComponent(
1034
if (instance !== null) {
1035
pushMarkerInstance(workInProgress, instance);
1036
}
1031
- const nextChildren = workInProgress.pendingProps.children;
1037
+ const nextChildren = nextProps.children;
1038
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
1039
return workInProgress.child;
1040
}
@@ -1076,7 +1082,7 @@ function updateProfiler(
1082
stateNode.passiveEffectDuration = -0;
1083
}
1084
}
1079
- const nextProps = workInProgress.pendingProps;
1085
+ const nextProps: ProfilerProps = workInProgress.pendingProps;
1086
const nextChildren = nextProps.children;
1087
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
1088
return workInProgress.child;
@@ -2084,7 +2090,7 @@ function updateSuspenseComponent(
2090
workInProgress: Fiber,
2091
renderLanes: Lanes,
2092
) {
2087
- const nextProps = workInProgress.pendingProps;
2093
+ const nextProps: SuspenseProps = workInProgress.pendingProps;
2094
2095
// This is used by DevTools to force a boundary to suspend.
2096
if (__DEV__) {
@@ -2677,7 +2683,7 @@ function updateDehydratedSuspenseComponent(
2683
workInProgress: Fiber,
2684
didSuspend: boolean,
2685
didPrimaryChildrenDefer: boolean,
2680
- nextProps: any,
2686
+ nextProps: SuspenseProps,
2687
suspenseInstance: SuspenseInstance,
2688
suspenseState: SuspenseState,
2689
renderLanes: Lanes,
packages/react-reconciler/src/ReactFiberCommitEffects.js
+14
-13
@@ -7,16 +7,19 @@
7
* @flow
8
*/
9
10
+import type {
11
+ ViewTransitionProps,
12
+ ProfilerProps,
13
+ ProfilerPhase,
14
+} from 'shared/ReactTypes';
15
import type {Fiber} from './ReactInternalTypes';
16
import type {UpdateQueue} from './ReactFiberClassUpdateQueue';
17
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
18
import type {HookFlags} from './ReactHookEffectTags';
19
import type {FragmentInstanceType} from './ReactFiberConfig';
15
-import {
16
- getViewTransitionName,
17
- type ViewTransitionState,
18
- type ViewTransitionProps,
19
-} from './ReactFiberViewTransitionComponent';
20
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
21
+
22
+import {getViewTransitionName} from './ReactFiberViewTransitionComponent';
23
24
import {
25
enableProfilerTimer,
@@ -938,9 +941,9 @@ function commitProfiler(
941
commitStartTime: number,
942
effectDuration: number,
943
) {
941
- const {id, onCommit, onRender} = finishedWork.memoizedProps;
944
+ const {id, onCommit, onRender} = (finishedWork.memoizedProps: ProfilerProps);
945
943
- let phase = current === null ? 'mount' : 'update';
946
+ let phase: ProfilerPhase = current === null ? 'mount' : 'update';
947
if (enableProfilerNestedUpdatePhase) {
948
if (isCurrentUpdateNested()) {
949
phase = 'nested-update';
@@ -951,8 +954,11 @@ function commitProfiler(
954
onRender(
955
id,
956
phase,
957
+ // $FlowFixMe: This should be always a number in profiling mode
958
finishedWork.actualDuration,
959
+ // $FlowFixMe: This should be always a number in profiling mode
960
finishedWork.treeBaseDuration,
961
+ // $FlowFixMe: This should be always a number in profiling mode
962
finishedWork.actualStartTime,
963
commitStartTime,
964
);
@@ -960,12 +966,7 @@ function commitProfiler(
966
967
if (enableProfilerCommitHooks) {
968
if (typeof onCommit === 'function') {
963
- onCommit(
964
- finishedWork.memoizedProps.id,
965
- phase,
966
- effectDuration,
967
- commitStartTime,
968
- );
969
+ onCommit(id, phase, effectDuration, commitStartTime);
970
}
971
}
972
}
packages/react-reconciler/src/ReactFiberCommitViewTransitions.js
+2
-4
@@ -7,12 +7,10 @@
7
* @flow
8
*/
9
10
+import type {ViewTransitionProps} from 'shared/ReactTypes';
11
import type {Instance, InstanceMeasurement, Props} from './ReactFiberConfig';
12
import type {Fiber} from './ReactInternalTypes';
12
-import type {
13
- ViewTransitionProps,
14
- ViewTransitionState,
15
-} from './ReactFiberViewTransitionComponent';
13
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
14
15
import {
16
HostComponent,
packages/react-reconciler/src/ReactFiberCommitWork.js
+2
-5
@@ -25,7 +25,7 @@ import {
25
import type {SuspenseState, RetryQueue} from './ReactFiberSuspenseComponent';
26
import type {UpdateQueue} from './ReactFiberClassUpdateQueue';
27
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
28
-import type {Wakeable} from 'shared/ReactTypes';
28
+import type {Wakeable, ViewTransitionProps} from 'shared/ReactTypes';
29
import type {
30
OffscreenState,
31
OffscreenInstance,
@@ -38,10 +38,7 @@ import type {
38
TracingMarkerInstance,
39
TransitionAbort,
40
} from './ReactFiberTracingMarkerComponent';
41
-import type {
42
- ViewTransitionProps,
43
- ViewTransitionState,
44
-} from './ReactFiberViewTransitionComponent';
41
+import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
42
43
import {
44
alwaysThrottleRetries,
packages/react-reconciler/src/ReactFiberDuplicateViewTransitions.js
+1
-1
@@ -8,7 +8,7 @@
8
*/
9
10
import type {Fiber} from './ReactInternalTypes';
11
-import type {ViewTransitionProps} from './ReactFiberViewTransitionComponent';
11
+import type {ViewTransitionProps} from 'shared/ReactTypes';
12
import {runWithFiberInDEV} from './ReactCurrentFiber';
13
14
// Use in DEV to track mounted named ViewTransitions. This is used to warn for
packages/react-reconciler/src/ReactFiberSuspenseComponent.js
+1
-13
@@ -7,7 +7,7 @@
7
* @flow
8
*/
9
10
-import type {ReactNodeList, Wakeable} from 'shared/ReactTypes';
10
+import type {Wakeable} from 'shared/ReactTypes';
11
import type {Fiber} from './ReactInternalTypes';
12
import type {SuspenseInstance} from './ReactFiberConfig';
13
import type {Lane} from './ReactFiberLane';
@@ -21,18 +21,6 @@ import {
21
isSuspenseInstanceFallback,
22
} from './ReactFiberConfig';
23
24
-export type SuspenseProps = {
25
- children?: ReactNodeList,
26
- fallback?: ReactNodeList,
27
-
28
- // TODO: Add "unstable_" prefix?
29
- suspenseCallback?: (Set<Wakeable> | null) => mixed,
30
-
31
- unstable_avoidThisFallback?: boolean,
32
- unstable_expectedLoadTime?: number,
33
- unstable_name?: string,
34
-};
35
-
24
// A null SuspenseState represents an unsuspended normal Suspense boundary.
25
// A non-null SuspenseState means that it is blocked for one reason or another.
26
// - A non-null dehydrated field means it's blocked pending hydration.
packages/react-reconciler/src/ReactFiberSuspenseContext.js
+2
-1
@@ -7,9 +7,10 @@
7
* @flow
8
*/
9
10
+import type {SuspenseProps} from 'shared/ReactTypes';
11
import type {Fiber} from './ReactInternalTypes';
12
import type {StackCursor} from './ReactFiberStack';
12
-import type {SuspenseProps, SuspenseState} from './ReactFiberSuspenseComponent';
13
+import type {SuspenseState} from './ReactFiberSuspenseComponent';
14
import type {OffscreenState} from './ReactFiberOffscreenComponent';
15
16
import {enableSuspenseAvoidThisFallback} from 'shared/ReactFeatureFlags';
packages/react-reconciler/src/ReactFiberViewTransitionComponent.js
+1
-25
@@ -7,7 +7,7 @@
7
* @flow
8
*/
9
10
-import type {ReactNodeList} from 'shared/ReactTypes';
10
+import type {ViewTransitionClass, ViewTransitionProps} from 'shared/ReactTypes';
11
import type {FiberRoot} from './ReactInternalTypes';
12
import type {ViewTransitionInstance, Instance} from './ReactFiberConfig';
13
@@ -20,30 +20,6 @@ import {getIsHydrating} from './ReactFiberHydrationContext';
20
21
import {getTreeId} from './ReactFiberTreeContext';
22
23
-export type ViewTransitionClassPerType = {
24
- [transitionType: 'default' | string]: 'none' | 'auto' | string,
25
-};
26
-
27
-export type ViewTransitionClass =
28
- | 'none'
29
- | 'auto'
30
- | string
31
- | ViewTransitionClassPerType;
32
-
33
-export type ViewTransitionProps = {
34
- name?: string,
35
- children?: ReactNodeList,
36
- default?: ViewTransitionClass,
37
- enter?: ViewTransitionClass,
38
- exit?: ViewTransitionClass,
39
- share?: ViewTransitionClass,
40
- update?: ViewTransitionClass,
41
- onEnter?: (instance: ViewTransitionInstance, types: Array<string>) => void,
42
- onExit?: (instance: ViewTransitionInstance, types: Array<string>) => void,
43
- onShare?: (instance: ViewTransitionInstance, types: Array<string>) => void,
44
- onUpdate?: (instance: ViewTransitionInstance, types: Array<string>) => void,
45
-};
46
-
23
export type ViewTransitionState = {
24
autoName: null | string, // the view-transition-name to use when an explicit one is not specified
25
paired: null | ViewTransitionState, // a temporary state during the commit phase if we have paired this with another instance
packages/react-server/src/ReactFizzServer.js
+5
-4
@@ -21,6 +21,9 @@ import type {
21
ReactFormState,
22
ReactComponentInfo,
23
ReactDebugInfo,
24
+ ViewTransitionProps,
25
+ ActivityProps,
26
+ SuspenseProps,
27
} from 'shared/ReactTypes';
28
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
29
import type {
@@ -35,8 +38,6 @@ import type {ComponentStackNode} from './ReactFizzComponentStack';
38
import type {TreeContext} from './ReactFizzTreeContext';
39
import type {ThenableState} from './ReactFizzThenable';
40
38
-import type {ActivityProps} from 'react-reconciler/src/ReactFiberActivityComponent';
39
-
41
import {describeObjectForErrorMessage} from 'shared/ReactSerializationErrors';
42
43
import {
@@ -1126,7 +1127,7 @@ function renderSuspenseBoundary(
1127
request: Request,
1128
someTask: Task,
1129
keyPath: KeyNode,
1129
- props: Object,
1130
+ props: SuspenseProps,
1131
): void {
1132
if (someTask.replay !== null) {
1133
// If we're replaying through this pass, it means we're replaying through
@@ -2255,7 +2256,7 @@ function renderViewTransition(
2256
request: Request,
2257
task: Task,
2258
keyPath: KeyNode,
2258
- props: Object,
2259
+ props: ViewTransitionProps,
2260
) {
2261
const prevKeyPath = task.keyPath;
2262
task.keyPath = keyPath;
packages/shared/ReactTypes.js
+75
@@ -235,3 +235,78 @@ export type ReactTimeInfo = {
235
export type ReactDebugInfo = Array<
236
ReactComponentInfo | ReactEnvironmentInfo | ReactAsyncInfo | ReactTimeInfo,
237
>;
238
+
239
+// Intrinsic ViewTransitionInstance. This type varies by Environment whether a particular
240
+// renderer supports it.
241
+export type ViewTransitionInstance = any;
242
+
243
+export type ViewTransitionClassPerType = {
244
+ [transitionType: 'default' | string]: 'none' | 'auto' | string,
245
+};
246
+
247
+export type ViewTransitionClass =
248
+ | 'none'
249
+ | 'auto'
250
+ | string
251
+ | ViewTransitionClassPerType;
252
+
253
+export type ViewTransitionProps = {
254
+ name?: string,
255
+ children?: ReactNodeList,
256
+ default?: ViewTransitionClass,
257
+ enter?: ViewTransitionClass,
258
+ exit?: ViewTransitionClass,
259
+ share?: ViewTransitionClass,
260
+ update?: ViewTransitionClass,
261
+ onEnter?: (instance: ViewTransitionInstance, types: Array<string>) => void,
262
+ onExit?: (instance: ViewTransitionInstance, types: Array<string>) => void,
263
+ onShare?: (instance: ViewTransitionInstance, types: Array<string>) => void,
264
+ onUpdate?: (instance: ViewTransitionInstance, types: Array<string>) => void,
265
+};
266
+
267
+export type ActivityProps = {
268
+ mode?: 'hidden' | 'visible' | null | void,
269
+ children?: ReactNodeList,
270
+};
271
+
272
+export type SuspenseProps = {
273
+ children?: ReactNodeList,
274
+ fallback?: ReactNodeList,
275
+
276
+ // TODO: Add "unstable_" prefix?
277
+ suspenseCallback?: (Set<Wakeable> | null) => mixed,
278
+
279
+ unstable_avoidThisFallback?: boolean,
280
+ unstable_expectedLoadTime?: number,
281
+ unstable_name?: string,
282
+};
283
+
284
+export type TracingMarkerProps = {
285
+ name: string,
286
+ children?: ReactNodeList,
287
+};
288
+
289
+export type CacheProps = {
290
+ children?: ReactNodeList,
291
+};
292
+
293
+export type ProfilerPhase = 'mount' | 'update' | 'nested-update';
294
+
295
+export type ProfilerProps = {
296
+ id?: string,
297
+ onRender?: (
298
+ id: void | string,
299
+ phase: ProfilerPhase,
300
+ actualDuration: number,
301
+ baseDuration: number,
302
+ startTime: number,
303
+ commitTime: number,
304
+ ) => void,
305
+ onCommit?: (
306
+ id: void | string,
307
+ phase: ProfilerPhase,
308
+ effectDuration: number,
309
+ commitTime: number,
310
+ ) => void,
311
+ children?: ReactNodeList,
312
+};