chore(types): enable exactOptionalPropertyTypes support#3719
chore(types): enable exactOptionalPropertyTypes support#3719YevheniiKotyrlo wants to merge 5 commits intosoftware-mansion:mainfrom
exactOptionalPropertyTypes support#3719Conversation
There was a problem hiding this comment.
Pull request overview
Enables TypeScript’s exactOptionalPropertyTypes across the repo and updates public and Fabric/codegen-facing type annotations to distinguish “missing” vs “explicitly undefined” optional props, improving compatibility for downstream consumers that enable the flag.
Changes:
- Enabled
exactOptionalPropertyTypesintsconfig.json. - Added
| undefinedto optional props across public types (src/types.tsx, SafeAreaView types) and internal Tabs parsing helper return types. - Updated Fabric codegen spec types under
src/fabric/**to be compatible withexactOptionalPropertyTypeswhile preserving codegen behavior.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Enables exactOptionalPropertyTypes for the project. |
| src/types.tsx | Adjusts several ScreenProps and GestureProps optional fields to allow explicit undefined. |
| src/components/safe-area/SafeAreaView.types.ts | Updates edges prop type to allow explicit undefined. |
| src/components/tabs/TabsScreen.tsx | Updates parseIconsToNativeProps return type optional fields to allow explicit undefined. |
| src/fabric/ScreenNativeComponent.ts | Updates optional event handler NativeProps to allow explicit undefined. |
| src/fabric/ModalScreenNativeComponent.ts | Updates optional event handler NativeProps to allow explicit undefined. |
| src/fabric/ScreenStackNativeComponent.ts | Updates onFinishTransitioning to allow explicit undefined. |
| src/fabric/ScreenStackHeaderConfigNativeComponent.ts | Updates optional event handlers / arrays to allow explicit undefined. |
| src/fabric/safe-area/SafeAreaViewNativeComponent.ts | Updates edges NativeProp type to allow explicit undefined. |
| src/fabric/tabs/TabsScreenNativeComponent.ts | Updates tab appearance-related optional fields to allow explicit undefined. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/types.tsx:168
- With
exactOptionalPropertyTypesenabled, optional props likeactive?: ...are still not assignable from a destructured/forwarded value of type... | undefined(e.g.const { active } = props; <Screen active={active} />). In this hunk onlyactivityState/shouldFreezewere updated; consider updatingactive(and other optionalScreenPropsfields that can be forwarded) to?: T | undefinedas well to fully address downstream eopt compatibility.
export interface ScreenProps extends ViewProps {
active?: 0 | 1 | Animated.AnimatedInterpolation<number>;
activityState?:
| 0
| 1
| 2
| Animated.AnimatedInterpolation<number>
| undefined;
/**
* Boolean indicating that the screen should be frozen with `react-freeze`.
*/
shouldFreeze?: boolean | undefined;
children?: React.ReactNode;
/**
* Boolean indicating that swipe dismissal should trigger animation provided by `stackAnimation`. Defaults to `false`.
*
* @platform ios
*/
customAnimationOnSwipe?: boolean;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
cc699a9 to
1db290d
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
1db290d to
cbab010
Compare
|
Hi, @YevheniiKotyrlo. Thank you for the PR. After internal discussion we decided to use |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
kligarski
left a comment
There was a problem hiding this comment.
By the way, we use in in ScreenStackHeaderConfig.tsx which is sensitive to not defined vs undefined but we should be good here. buttonId and menuId are internal props set to some value and items is a required property.
| @@ -3,12 +3,14 @@ import type { ScrollEdgeEffect } from '../../shared/types'; | |||
|
|
|||
| export interface ScrollViewMarkerProps { | |||
| children: ViewProps['children']; | |||
There was a problem hiding this comment.
We can consider adding undefined to this prop or removing nullability from ViewProps['children'].
There was a problem hiding this comment.
children is required here (no ?), so exactOptionalPropertyTypes doesn't actually constrain it — the flag only affects optional props. ViewProps['children'] is React.ReactNode | undefined (and React.ReactNode itself already includes null | undefined), so forwarded values stay assignable to this required prop regardless. Happy to leave as-is for this PR, or to make it optional (children?: ViewProps['children']) for consistency with the rest of the interface — let me know which you prefer.
…operty-types # Conflicts: # src/components/gamma/scroll-view-marker/ScrollViewMarker.types.ts # src/components/tabs/host/TabsHost.types.ts # src/components/tabs/host/useTabsHost.ts # src/components/tabs/screen/TabsScreen.ios.types.ts
|
Thanks @kligarski — really appreciate you taking it further. Broadening to all non-required props is the right call for API consistency, no objections at all. Just pushed a merge with latest Quality gates all pass locally: On the Also — I've refreshed the PR description to match the broader post-takeover scope (41 files, not the original 10) and to update the codegen verification command against the current Fabric file layout. The old description was stale. CI workflows are currently in |
Description
This PR enables TypeScript's
exactOptionalPropertyTypesflag in the repo and adds| undefinedto every non-required prop so the flag stays on cleanly.exactOptionalPropertyTypesis a strict TypeScript flag (not included instrict: true) that distinguishes between "property is missing" and "property is explicitlyundefined". When enabled,prop?: Tmeans the property can be omitted but cannot be set toundefined— the fix isprop?: T | undefined.This matters for downstream projects that enable this flag — without this change, they get type errors when passing destructured props from
react-native-screenscomponents. This is currently blocking react-navigation from enabling the flag — 17 of 22@ts-expect-errordirectives in that PR come fromreact-native-screenstypes.Changes
The initial commit fixed only the 13 concrete eopt errors (14 after the later Tabs refactor). After internal discussion, @kligarski broadened the scope to every non-required prop across the codebase for a consistent public API — commits
14c3927d8("add undefined to all non-required props") andbebd04cba("remove undefined after CT.WithDefault to satisfy codegen"). The merge commitbf4c49ab3integrates latestmainand resolves the 4 conflicts from theScrollViewMarkermigration (#3895) andcontrolNavigationStateInJSremoval (#3888).Current diff: 41 files, +722/-605
tsconfig.json(enables flag),src/types.tsx(all non-required props inScreenProps,GestureProps, etc.).types.ts.tsx/.tsDebugContainer,FullWindowOverlay,ScreenFooter,ScreenStackHeaderConfig.web,ScreenStackItem,SearchBar,TabsScreen.android,TabsScreen.ios,useTabsScreen,useTabsHostModalScreenNativeComponent,ScreenNativeComponent,ScreenStackHeaderConfigNativeComponent,ScreenStackHeaderSubviewNativeComponent,ScreenStackNativeComponent,SearchBarNativeComponentgamma/split/*(2),gamma/stack/StackScreenNativeComponent,safe-area/SafeAreaViewNativeComponent,tabs/*(5: TabsBottomAccessory, TabsHostAndroid/IOS, TabsScreenAndroid/IOS)All changes are type annotations only — zero runtime changes.
Codegen compatibility
The
src/fabric/spec files are consumed by@react-native/codegen. Adding| undefinedto optional properties is safe — the codegen parser (parseTopLevelType.js) explicitly stripsundefinedfrom union types and treats the result identically toprop?: T.Exception:
CT.WithDefault<T, V>props are NOT modified —WithDefaultalready expands toT | undefined | nullso it's already eopt-compatible, and combining it with| undefinedcrashes the codegen parser ("WithDefault<> is optional and does not need to be marked as optional"). Commitbebd04cbaremoves the stray| undefinedadditions after anyCT.WithDefault<>for exactly this reason.I verified the codegen schema output is byte-identical between
mainand this branch across all 23 current Fabric spec files:Run on both
origin/mainand this branch,diff -qexits 0.Test plan
yarn check-typespasses with 0 errors (withexactOptionalPropertyTypesenabled)yarn lint-jspasses with 0 errors and the same 18 pre-existing warnings asorigin/mainyarn prettier --check src/is cleanmainacross all 23src/fabric/**NativeComponent.tsfilesChecklist