What happened?
Uniwind types className by augmenting react-native with declare module interfaces (ViewProps, TextProps, ScrollViewProps, … in types.d.ts, pulled in via the generated d.ts's /// <reference types="uniwind/types" />).
Under React Native's Strict TypeScript API — opt-in via customConditions: ["react-native", "react-native-strict-api"] on 0.80–0.86, the default from RN 0.87 — those same props are generated type aliases, and TypeScript cannot merge an interface with a type alias:
- With
skipLibCheck: false: hard TS6200 — "Definitions of the following identifiers conflict with those in another file" — across 18 prop types (ViewProps, TextProps, PressableProps, TextInputProps, FlatListProps, ScrollViewProps, SwitchProps, …).
- With
skipLibCheck: true (the common config): the interface silently wins — root ViewProps/TextProps collapse to className-only, losing children, accessibilityLabel, everything — and it cascades into any library building on them (@shopify/flash-list, @shopify/react-native-skia, react-native-reorderable-list). 243 type errors in our app.
Two workarounds we verified do not work, to save triage time:
- tsconfig
paths stubbing cannot intercept the triple-slash type reference route (error count unchanged).
- The generated per-app d.ts is regenerated by the CLI, so editing it is not durable.
What we ship instead (works, but is scaffolding every strict-mode app would need to reinvent): strip the /// <reference> line from the generated d.ts post-generation, and type className locally via intersection — ComponentProps<typeof View> & { className?: string } — which the Strict API supports where augmentation cannot. The runtime is unaffected throughout: the Metro nativeResolver rewrite of react-native → uniwind/components carries className regardless of types.
Ask: strict-compatible typing — e.g. a parallel types entry keyed on the react-native-strict-api custom condition, or intersection-based component typing instead of global interface augmentation. This becomes non-optional for every Uniwind app when RN 0.87 makes the Strict API the default.
Steps to Reproduce
- Expo SDK 57 app, RN 0.86.3,
uniwind@1.11.0 wired per docs (withUniwindConfig, generated d.ts included in tsconfig).
- Add
"customConditions": ["react-native", "react-native-strict-api"] to compilerOptions (with "moduleResolution": "bundler").
tsc --noEmit → mass prop-type errors (or TS6200 with skipLibCheck: false).
Snack or Repository Link
Private repo; the measurement table and the full analysis are reproducible from the steps above (numbers: 243 errors with the augmentation loaded; 3 without it — the 3 being className itself; 0 after the intersection-typing workaround).
Uniwind version
1.11.0
React Native Version
0.86.3
Platforms
iOS, Android
Expo
Yes — SDK 57
Additional information
Filed ahead of moving this app to Uniwind Pro. Happy to test a fix build — the strict opt-in is enabled in our CI, so a compatible release gets verified within a day.
What happened?
Uniwind types
classNameby augmentingreact-nativewithdeclare moduleinterfaces (ViewProps,TextProps,ScrollViewProps, … intypes.d.ts, pulled in via the generated d.ts's/// <reference types="uniwind/types" />).Under React Native's Strict TypeScript API — opt-in via
customConditions: ["react-native", "react-native-strict-api"]on 0.80–0.86, the default from RN 0.87 — those same props are generated type aliases, and TypeScript cannot merge an interface with a type alias:skipLibCheck: false: hardTS6200— "Definitions of the following identifiers conflict with those in another file" — across 18 prop types (ViewProps,TextProps,PressableProps,TextInputProps,FlatListProps,ScrollViewProps,SwitchProps, …).skipLibCheck: true(the common config): the interface silently wins — rootViewProps/TextPropscollapse toclassName-only, losingchildren,accessibilityLabel, everything — and it cascades into any library building on them (@shopify/flash-list,@shopify/react-native-skia,react-native-reorderable-list). 243 type errors in our app.Two workarounds we verified do not work, to save triage time:
pathsstubbing cannot intercept the triple-slash type reference route (error count unchanged).What we ship instead (works, but is scaffolding every strict-mode app would need to reinvent): strip the
/// <reference>line from the generated d.ts post-generation, and typeclassNamelocally via intersection —ComponentProps<typeof View> & { className?: string }— which the Strict API supports where augmentation cannot. The runtime is unaffected throughout: the MetronativeResolverrewrite ofreact-native→uniwind/componentscarriesclassNameregardless of types.Ask: strict-compatible typing — e.g. a parallel types entry keyed on the
react-native-strict-apicustom condition, or intersection-based component typing instead of global interface augmentation. This becomes non-optional for every Uniwind app when RN 0.87 makes the Strict API the default.Steps to Reproduce
uniwind@1.11.0wired per docs (withUniwindConfig, generated d.ts included in tsconfig)."customConditions": ["react-native", "react-native-strict-api"]tocompilerOptions(with"moduleResolution": "bundler").tsc --noEmit→ mass prop-type errors (orTS6200withskipLibCheck: false).Snack or Repository Link
Private repo; the measurement table and the full analysis are reproducible from the steps above (numbers: 243 errors with the augmentation loaded; 3 without it — the 3 being
classNameitself; 0 after the intersection-typing workaround).Uniwind version
1.11.0
React Native Version
0.86.3
Platforms
iOS, Android
Expo
Yes — SDK 57
Additional information
Filed ahead of moving this app to Uniwind Pro. Happy to test a fix build — the strict opt-in is enabled in our CI, so a compatible release gets verified within a day.