Fix missing ViewStyle properties on legacy TypeScript ImageStyle - #57938
Open
giaBaoJS wants to merge 1 commit into
Open
Fix missing ViewStyle properties on legacy TypeScript ImageStyle#57938giaBaoJS wants to merge 1 commit into
giaBaoJS wants to merge 1 commit into
Conversation
The hand-written `ImageStyle` interface in `types_DEPRECATED` redeclared a small subset of `ViewStyle` properties instead of extending it, so newer style props such as `filter`, `boxShadow`, `mixBlendMode`, `outlineColor` and `pointerEvents` were rejected on `<Image>` styles. Both other sources of truth already include them: the Flow `____ImageStyle_InternalCore` spreads `$Exact<____ViewStyle_Internal>`, and the generated strict API declares `Omit<____ViewStyle_Internal, 'overflow'>`. Extend `ViewStyle` with `overflow` omitted, mirroring the strict API, so `overflow` stays narrowed to 'visible' | 'hidden' on images.
Member
|
Hey @giaBaoJS, thanks for looking into this. I don't know if we want to merge this right now, as #52957 was opened in mid-2025 and we've since deprecated the legacy manual types — it's probably better to keep those code-locked rather than delivering a minor fix/breaking change this late in the game. Sorry about that. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Fixes #52957
The hand-written (legacy) TypeScript
ImageStyleinterface redeclares a small subset ofViewStyle's properties instead of extending it. As a result, style properties added toViewStyleover time —filter,boxShadow,mixBlendMode,outlineColor/outlineOffset/outlineStyle/outlineWidth,pointerEvents,elevation,isolation,borderCurve,backgroundImage, the logical border-radius/border-color properties, and theexperimental_background*set — are rejected on<Image>styles, even though they are supported at runtime.This is a divergence between three sources of truth, not a design choice
ViewStyleprops?Libraries/StyleSheet/StyleSheetTypes.js:1052____ImageStyle_InternalCore = Readonly<{...$Exact<____ViewStyle_Internal>, resizeMode?, objectFit?, tintColor?, overlayColor?, overflow?}>____ViewStyle_InternalReactNativeApi.d.ts:619____ImageStyle_InternalCore = Readonly<Omit<____ViewStyle_Internal, "overflow"> & {...}>types_DEPRECATED/Libraries/StyleSheet/StyleSheetTypes.d.ts:641interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyleThis matches @huntie's diagnosis in #52957: the bug is in the manual types only, and the
react-native-strict-apiopt-in is already correct.Scope:
ImageStyleonly — theTextStylehalf of the report is already fixed onmainThe issue title says "
ImageStyleandTextStyle", but onlyImageStyleis affected today.StyleSheetTypes.d.ts:562already readsexport interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle, soTextStyleinherits everything. I verified this with atscprobe against the legacy types: aTextStyleobject literal containingfilter,boxShadow,mixBlendMode,outlineColor, andisolationtypechecks cleanly on unmodifiedmain. Keeping this PR scoped toImageStyleis deliberate.How
overflowis handledImageStylecannot simplyextend ViewStyle:ViewStyleinheritsoverflow?: 'visible' | 'hidden' | 'scroll'fromFlexStyle, while both Flow and the strict API deliberately narrow it to'visible' | 'hidden'for images. This PR mirrors the strict API exactly —extends Omit<ViewStyle, 'overflow'>, then redeclares the narrowedoverflow. There is a type test asserting'scroll'is still rejected.The nine other properties removed from the interface body are now inherited from
ViewStyle. I confirmed each one keeps a byte-identical type viaExact<>type-level assertions (see Test Plan), so this is a pure widening with no change to any previously-valid style.Changelog:
[GENERAL] [FIXED] - Add missing
ViewStyleproperties (filter,boxShadow,mixBlendMode,outlineColor,pointerEvents, and others) to the legacy TypeScriptImageStyletypeTest Plan:
Added
packages/react-native/__typetests__/stylesheet-image-style.tsx, which runs under bothtsconfig.legacy.json(hand-written types) andtsconfig.json(generated strict API), so the two stay aligned.Counterfactual — the test fails without the fix. With only the interface change reverted (test file kept):
Restoring the fix:
User-visible path verified. The second error above is the real-world symptom —
<Image style={{filter: 'brightness(0.5)', mixBlendMode: 'multiply'}} />, i.e. an app author writingViewStyleproperties inline on anImage. (filterproduces a confusing message becauseStyleProp<ImageStyle>may be an array, so TS matches it againstArray.prototype.filter.) The type test covers both this JSX path and directImageStyleannotations.Each property from the issue report, individually, before the fix (
const s: ImageStyle = {<prop>}compiled withtsc -p tsconfig.legacy.json):All pass after the fix.
No regression for existing consumers. Type-level
Exact<A, B>assertions confirm every property removed from the interface body resolves to an identical type through inheritance, and thatoverflow/resizeModeare unchanged — all 12 pass:backfaceVisibility,borderBottomLeftRadius,borderBottomRightRadius,backgroundColor,borderColor,borderRadius,borderTopLeftRadius,borderTopRightRadius,opacity,cursor,overflow,resizeMode.Full gates, all green:
yarn test-typescript-legacyDone in 0.78s)yarn test-generated-typescriptDone in 0.84s)yarn testyarn eslint --max-warnings 0 <changed files>prettier --check <changed files>yarn build-typesgit statusclean, confirming the strict API is untouched