@samitouri / QOS-React / commits / c44e4a2505

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 +};