diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index a32823cb5f8b5..48f4fec6ad837 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -595,7 +595,7 @@ export const EnvironmentConfigSchema = z.object({ enableCustomTypeDefinitionForReanimated: z.boolean().default(false), /** - * If specified, this value is used as a pattern for determing which global values should be + * If specified, this value is used as a pattern for determining which global values should be * treated as hooks. The pattern should have a single capture group, which will be used as * the hook name for the purposes of resolving hook definitions (for builtin hooks)_. * @@ -608,8 +608,8 @@ export const EnvironmentConfigSchema = z.object({ hookPattern: z.string().nullable().default(null), /** - * If enabled, this will treat objects named as `ref` or if their names end with the substring `Ref`, - * and contain a property named `current`, as React refs. + * If enabled, this will treat objects named as `ref` or if their names end with substring `Ref` + * or `_ref`, and contain a property named `current`, as React refs. * * ``` * const ref = useMyRef(); @@ -620,7 +620,7 @@ export const EnvironmentConfigSchema = z.object({ * }) * ``` * - * Here the variables `ref` and `myRef` will be typed as Refs. + * Here the variables `ref`, `myRef`, and `my_ref` will be typed as Refs. */ enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(true), diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index b6ec11fdb4ff9..3cfcc158eae45 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -840,7 +840,7 @@ class Unifier { } } -const RefLikeNameRE = /^(?:[a-zA-Z$_][a-zA-Z$_0-9]*)Ref$|^ref$/; +const RefLikeNameRE = /^(?:[a-zA-Z$_][a-zA-Z$_0-9]*)(?:R|_r)ef$|^ref$/; function isRefLikeName(t: PropType): boolean { return ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.expect.md new file mode 100644 index 0000000000000..a314ad2504915 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.expect.md @@ -0,0 +1,83 @@ + +## Input + +```javascript +// @enableTreatRefLikeIdentifiersAsRefs @validatePreserveExistingMemoizationGuarantees +import {useRef, useCallback} from 'react'; + +function useCustomRef() { + return useRef({click: () => {}}); +} + +function Foo() { + const custom_ref = useCustomRef(); + + const onClick = useCallback(() => { + custom_ref.current?.click(); + }, [custom_ref]); + + return \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.js new file mode 100644 index 0000000000000..adfc29c111a61 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-3.js @@ -0,0 +1,22 @@ +// @enableTreatRefLikeIdentifiersAsRefs @validatePreserveExistingMemoizationGuarantees +import {useRef, useCallback} from 'react'; + +function useCustomRef() { + return useRef({click: () => {}}); +} + +function Foo() { + const custom_ref = useCustomRef(); + + const onClick = useCallback(() => { + custom_ref.current?.click(); + }, [custom_ref]); + + return