Skip to content

Fix missing ViewStyle properties on legacy TypeScript ImageStyle - #57938

Open
giaBaoJS wants to merge 1 commit into
react:mainfrom
giaBaoJS:fix-imagestyle-missing-viewstyle-props
Open

Fix missing ViewStyle properties on legacy TypeScript ImageStyle#57938
giaBaoJS wants to merge 1 commit into
react:mainfrom
giaBaoJS:fix-imagestyle-missing-viewstyle-props

Conversation

@giaBaoJS

Copy link
Copy Markdown

Summary:

Fixes #52957

The hand-written (legacy) TypeScript ImageStyle interface redeclares a small subset of ViewStyle's properties instead of extending it. As a result, style properties added to ViewStyle over time — filter, boxShadow, mixBlendMode, outlineColor/outlineOffset/outlineStyle/outlineWidth, pointerEvents, elevation, isolation, borderCurve, backgroundImage, the logical border-radius/border-color properties, and the experimental_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

Source Definition Includes ViewStyle props?
Flow (authoritative)Libraries/StyleSheet/StyleSheetTypes.js:1052 ____ImageStyle_InternalCore = Readonly<{...$Exact<____ViewStyle_Internal>, resizeMode?, objectFit?, tintColor?, overlayColor?, overflow?}> Yes — spreads ____ViewStyle_Internal
Generated strict APIReactNativeApi.d.ts:619 ____ImageStyle_InternalCore = Readonly<Omit<____ViewStyle_Internal, "overflow"> & {...}> Yes
Legacy hand-written TStypes_DEPRECATED/Libraries/StyleSheet/StyleSheetTypes.d.ts:641 interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle No — the sole outlier

This matches @huntie's diagnosis in #52957: the bug is in the manual types only, and the react-native-strict-api opt-in is already correct.

Scope: ImageStyle only — the TextStyle half of the report is already fixed on main

The issue title says "ImageStyle and TextStyle", but only ImageStyle is affected today. StyleSheetTypes.d.ts:562 already reads export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle, so TextStyle inherits everything. I verified this with a tsc probe against the legacy types: a TextStyle object literal containing filter, boxShadow, mixBlendMode, outlineColor, and isolation typechecks cleanly on unmodified main. Keeping this PR scoped to ImageStyle is deliberate.

How overflow is handled

ImageStyle cannot simply extend ViewStyle: ViewStyle inherits overflow?: 'visible' | 'hidden' | 'scroll' from FlexStyle, 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 narrowed overflow. 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 via Exact<> 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 ViewStyle properties (filter, boxShadow, mixBlendMode, outlineColor, pointerEvents, and others) to the legacy TypeScript ImageStyle type

Test Plan:

Added packages/react-native/__typetests__/stylesheet-image-style.tsx, which runs under both tsconfig.legacy.json (hand-written types) and tsconfig.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):

$ yarn test-typescript-legacy
packages/react-native/__typetests__/stylesheet-image-style.tsx(19,3): error TS2353: Object literal may only specify known properties, and 'backgroundImage' does not exist in type 'ImageStyle'.
packages/react-native/__typetests__/stylesheet-image-style.tsx(71,9): error TS2769: No overload matches this call.
error Command failed with exit code 2.

Restoring the fix:

$ yarn test-typescript-legacy
Done in 0.78s.

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 writing ViewStyle properties inline on an Image. (filter produces a confusing message because StyleProp<ImageStyle> may be an array, so TS matches it against Array.prototype.filter.) The type test covers both this JSX path and direct ImageStyle annotations.

Each property from the issue report, individually, before the fix (const s: ImageStyle = {<prop>} compiled with tsc -p tsconfig.legacy.json):

filter        -> error TS2353: ... 'filter' does not exist in type 'ImageStyle'.
boxShadow     -> error TS2353: ... 'boxShadow' does not exist in type 'ImageStyle'.
mixBlendMode  -> error TS2353: ... 'mixBlendMode' does not exist in type 'ImageStyle'.
outlineColor  -> error TS2353: ... 'outlineColor' does not exist in type 'ImageStyle'.
pointerEvents -> error TS2353: ... 'pointerEvents' does not exist in type 'ImageStyle'.

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 that overflow/resizeMode are unchanged — all 12 pass:

backfaceVisibility, borderBottomLeftRadius, borderBottomRightRadius, backgroundColor, borderColor, borderRadius, borderTopLeftRadius, borderTopRightRadius, opacity, cursor, overflow, resizeMode.

Full gates, all green:

Command Result
yarn test-typescript-legacy Pass (Done in 0.78s)
yarn test-generated-typescript Pass (Done in 0.84s)
yarn test 218 suites / 5585 passed, 1 skipped, 1666 snapshots — 0 failures
yarn eslint --max-warnings 0 <changed files> Clean
prettier --check <changed files> Clean
yarn build-types API snapshot regenerates byte-identicalgit status clean, confirming the strict API is untouched

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.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 13, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Aug 13, 2026
@huntie

huntie commented Aug 13, 2026

Copy link
Copy Markdown
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[TypeScript] Properties missing in ImageStyle and TextStyle type

2 participants