Skip to content

Fix NoCodes TurboModule spec failing Codegen on React Native 0.84+#446

Open
NickSxti wants to merge 1 commit into
developfrom
nch/fix-nocodes-turbomodule-codegen
Open

Fix NoCodes TurboModule spec failing Codegen on React Native 0.84+#446
NickSxti wants to merge 1 commit into
developfrom
nch/fix-nocodes-turbomodule-codegen

Conversation

@NickSxti

Copy link
Copy Markdown
Contributor

Problem

Installing the SDK in a New Architecture app on React Native 0.84+ fails at the Codegen step, aborting pod install (and the Android Codegen task) with:

UnsupportedGenericParserError: Module NativeNoCodesModule: Unrecognized generic type 'QNoCodeAction' in NativeModule spec.

This happens for every New Architecture app on RN 0.84+, on both iOS and Android, whether or not the app uses No-Codes, because Codegen processes the whole spec directory at build time. Since RN 0.82+ no longer allows opting out of the New Architecture, there is no workaround at the app level.

Root cause

src/internal/specs/NativeNoCodesModule.ts typed the onNoCodeEvent event-emitter payload as a union of types imported from another module:

import type { QNoCodeAction, QNoCodesError, QNoCodeScreenInfo } from '../Mapper';

export type NoCodeEvent = {
  name: string;
  payload: QNoCodeAction | QNoCodesError | QNoCodeScreenInfo | undefined;
};

readonly onNoCodeEvent: EventEmitter<NoCodeEvent>;

React Native Codegen resolves only the types declared inside the spec file - it does not follow import declarations. Up to RN 0.83 this was latent because Codegen treated the emitter payload as an opaque alias and never descended into it. RN 0.84 changed Codegen to fully resolve an event emitter's payload type, so the imported QNoCodeAction can no longer be resolved and Codegen throws. (The imported types are also not Codegen-representable on their own: a union of distinct object types, an intersection type, and a Map.)

The sibling NativeQonversionModule spec is unaffected because its imported types appear only in Promise<...> returns, which Codegen degrades gracefully.

Fix

Type onNoCodeEvent as EventEmitter<Object>, identical to every other emitter already shipping in the SDK (onNoCodePurchase, and onEntitlementsUpdated / onDeferredPurchaseCompleted in NativeQonversionModule). The NoCodeEvent payload type moves to its only consumer, NoCodesInternal, and the event handler casts the opaque payload back to NoCodeEvent in the JS layer - the same pattern customPurchaseHandler already uses.

The native module spec is now self-contained (it imports nothing from ../Mapper), so a future change to the mapper types cannot reintroduce this failure.

Runtime impact

None. Native still emits a plain { name, payload } dictionary; the as casts are erased at build time. All six No-Codes listener callbacks and the purchase/restore delegate flow are unchanged. No native iOS/Android code is touched.

Verification

  • @react-native/codegen 0.85.3: the spec now parses successfully with all three emitters preserved (onNoCodeEvent, onNoCodePurchase, onNoCodeRestore); the full native generators (iOS Obj-C++, C++, Android Java/JNI) run without error. The same harness reproduces the original UnsupportedGenericParserError on the unpatched spec.
  • tsc (strict): no new errors.
  • jest: all unit tests pass.

Workaround for affected users (until released)

In node_modules/@qonversion/react-native-sdk/src/internal/specs/NativeNoCodesModule.ts, change EventEmitter<NoCodeEvent> to EventEmitter<Object>, then run npx patch-package @qonversion/react-native-sdk and cd ios && pod install.

The NoCodes TurboModule spec typed the `onNoCodeEvent` emitter payload as
a union of types imported from `../Mapper`. React Native Codegen only
resolves types declared inside the spec file, and since RN 0.84 it fully
descends into an event emitter's payload type alias. It therefore cannot
resolve the imported `QNoCodeAction` and throws:

  UnsupportedGenericParserError: Module NativeNoCodesModule:
  Unrecognized generic type 'QNoCodeAction' in NativeModule spec.

This aborts `pod install` for every New Architecture app on RN 0.84+
(iOS and Android), regardless of whether the app uses No-Codes, because
Codegen processes the whole spec directory at build time. RN 0.82+ no
longer lets apps opt out of the New Architecture, so there is no escape
hatch.

Type `onNoCodeEvent` as `EventEmitter<Object>`, matching every other
emitter in the SDK (`onNoCodePurchase`, `onEntitlementsUpdated`, ...),
and move the `NoCodeEvent` payload type to its only consumer
(`NoCodesInternal`). The native boundary now carries an opaque payload
that Codegen resolves natively; the handler casts it back in the JS
layer, exactly as `customPurchaseHandler` already does. Runtime is
unchanged - native still emits a `{ name, payload }` dictionary.

Verified with @react-native/codegen 0.85.3: the spec parses with all
three emitters preserved (`onNoCodeEvent`, `onNoCodePurchase`,
`onNoCodeRestore`); typecheck and unit tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@NickSxti NickSxti requested a review from SpertsyanKM June 29, 2026 13:22
@NickSxti

Copy link
Copy Markdown
Contributor Author

@SpertsyanKM could you review this when you get a chance?

It fixes the React Native Codegen failure that breaks pod install on the New Architecture for RN 0.84+ (UnsupportedGenericParserError: Unrecognized generic type 'QNoCodeAction' in NativeModule spec). Codegen processes the whole spec directory at build time, so this currently blocks installing the SDK in any New-Arch app on RN 0.84+, on both iOS and Android, regardless of whether the app uses No-Codes.

The fix types onNoCodeEvent as EventEmitter<Object> to match the other emitters in the SDK and moves the NoCodeEvent payload type to its only consumer (NoCodesInternal), so the native spec no longer imports domain types. Runtime is unchanged - native still emits a { name, payload } dictionary. Verified against @react-native/codegen 0.85.3: the spec parses with all three emitters preserved and the native generators (iOS/C++/Android) run clean; typecheck and unit tests pass.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants