From 87752e926dda33d2ed2879f4504ccc96aad1f54e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Jul 2026 12:07:08 -0400 Subject: [PATCH] fix(codegen): accept React.ComponentRef in command first-arg React 19 renamed `React.ElementRef` to `React.ComponentRef`. The TypeScript commands parser only accepts `ElementRef`, so a NativeCommand whose first arg is typed as `React.ComponentRef` fails codegen with "The first argument of method must be of type React.ElementRef<>". Forward-ports facebook/react-native#54274 (by Mike Hardy): accept both names and update the error message. This unblocks libraries that moved to `ComponentRef`, like react-native-screens 4.26, whose command spec currently breaks the macOS codegen. --- .../components/__test_fixtures__/fixtures.js | 28 +++++++++---------- .../typescript-component-parser-test.js.snap | 4 +-- .../parsers/typescript/components/commands.js | 5 ++-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js index 7e3f86b265c5..79cbdc22b3ba 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js @@ -1062,17 +1062,17 @@ export interface ModuleProps extends ViewProps { type NativeType = HostComponent; interface NativeCommands { - readonly handleRootTag: (viewRef: React.ElementRef, rootTag: RootTag) => void; - readonly hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void; + readonly handleRootTag: (viewRef: React.ComponentRef, rootTag: RootTag) => void; + readonly hotspotUpdate: (viewRef: React.ComponentRef, x: Int32, y: Int32) => void; scrollTo( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, x: Float, y: Int32, z: Double, animated: boolean, ): void; readonly arrayArgs: ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, booleanArray: ReadOnlyArray, stringArray: ReadOnlyArray, floatArray: ReadOnlyArray, @@ -1122,12 +1122,12 @@ export interface ModuleProps extends ViewProps { type NativeType = HostComponent; export type ScrollTo = ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, y: Int, animated: Boolean, ) => Void; export type AddOverlays = ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, overlayColorsReadOnly: ReadOnlyArray, overlayColorsArray: Array, overlayColorsArrayAnnotation: string[], @@ -1193,7 +1193,7 @@ export interface ModuleNativeState { type NativeType = HostComponent; -export type ScrollTo = (viewRef: React.ElementRef, y: Int, animated: Boolean) => Void; +export type ScrollTo = (viewRef: React.ComponentRef, y: Int, animated: Boolean) => Void; interface NativeCommands { readonly scrollTo: ScrollTo; @@ -2184,17 +2184,17 @@ export interface ModuleProps extends ViewProps { type NativeType = HostComponent; interface NativeCommands { - readonly handleRootTag: (viewRef: React.ElementRef, rootTag: RootTag) => void; - readonly hotspotUpdate: (viewRef: React.ElementRef, x: CodegenTypes.Int32, y: CodegenTypes.Int32) => void; + readonly handleRootTag: (viewRef: React.ComponentRef, rootTag: RootTag) => void; + readonly hotspotUpdate: (viewRef: React.ComponentRef, x: CodegenTypes.Int32, y: CodegenTypes.Int32) => void; scrollTo( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, x: CodegenTypes.Float, y: CodegenTypes.Int32, z: CodegenTypes.Double, animated: boolean, ): void; readonly arrayArgs: ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, booleanArray: ReadOnlyArray, stringArray: ReadOnlyArray, floatArray: ReadOnlyArray, @@ -2243,12 +2243,12 @@ export interface ModuleProps extends ViewProps { type NativeType = HostComponent; export type ScrollTo = ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, y: Int, animated: Boolean, ) => Void; export type AddOverlays = ( - viewRef: React.ElementRef, + viewRef: React.ComponentRef, overlayColorsReadOnly: ReadOnlyArray, overlayColorsArray: Array, overlayColorsArrayAnnotation: string[], @@ -2310,7 +2310,7 @@ export interface ModuleNativeState { type NativeType = HostComponent; -export type ScrollTo = (viewRef: React.ElementRef, y: Int, animated: Boolean) => Void; +export type ScrollTo = (viewRef: React.ComponentRef, y: Int, animated: Boolean) => Void; interface NativeCommands { readonly scrollTo: ScrollTo; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap index 6c2f40bc7eb8..cd6ea9408f26 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap @@ -6,11 +6,11 @@ exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_ exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITH_MISMATCHED_METHOD_NAMES 1`] = `"codegenNativeCommands expected the same supportedCommands specified in the NativeCommands interface: hotspotUpdate, scrollTo"`; -exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITH_NULLABLE_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<>"`; +exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITH_NULLABLE_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<> or React.ComponentRef<>"`; exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITHOUT_METHOD_NAMES 1`] = `"codegenNativeCommands must be passed options including the supported commands"`; -exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<>"`; +exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<> or React.ComponentRef<>"`; exports[`RN Codegen TypeScript Parser Fails with error message NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE 1`] = `"key required_key_with_default must be optional if used with WithDefault<> annotation"`; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/commands.js b/packages/react-native-codegen/src/parsers/typescript/components/commands.js index 272eeb3be2c1..bf46e2a53f65 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/commands.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/commands.js @@ -38,11 +38,12 @@ function buildCommandSchemaInternal( firstParam.typeAnnotation != null && firstParam.typeAnnotation.type === 'TSTypeReference' && firstParam.typeAnnotation.typeName.left?.name === 'React' && - firstParam.typeAnnotation.typeName.right?.name === 'ElementRef' + (firstParam.typeAnnotation.typeName.right?.name === 'ElementRef' || + firstParam.typeAnnotation.typeName.right?.name === 'ComponentRef') ) ) { throw new Error( - `The first argument of method ${name} must be of type React.ElementRef<>`, + `The first argument of method ${name} must be of type React.ElementRef<> or React.ComponentRef<>`, ); }