Commit 778ae87
Fix ref type compatibility for builtin components (#56673)
Summary:
Fix `useRef` and `forwardRef` backcompat when migrating to React Native's generated TypeScript types (Strict TypeScript API).
Previously this was an awkward breaking change: https://reactnative.dev/docs/strict-typescript-api#some-core-components-are-now-function-components-instead-of-class-components
```diff
- const ref = useRef<View>(null);
+ const ref = useRef<React.ComponentRef<typeof View>>(null);
```
After this diff, no workaround will be required.
**Changes**
- Add companion type aliases alongside each component's value export.
- Introduces a new `/* ts-only */` comment syntax in `index.js.flow` to hide the companion exports from Flow, which has no equivalent concept of declaration merging.
**Problem detail**
In our Flow source code, built-in components like `View` and `TextInput` are function components rather than classes. This differs from the previous manual `.d.ts` files which [defined each component as a class](https://github.com/facebook/react-native/blob/d1cdce24cca2224f8d37873d24a49523a8271a0a/packages/react-native/Libraries/Text/Text.d.ts#L226).
In TypeScript, a class name serves as both a value (the constructor) and a type (the instance), so patterns like `useRef<View>()` work. However, with function components, the name is only a value (the function signature) making `useRef<View>()` resolve to a ref holding the function itself, not the native element.
**The fix**: Add companion type aliases alongside each component's value export. TypeScript's declaration merging makes the component name simultaneously a value (for JSX) and a type (for refs).
```diff
// Before — required workaround
- const ref = useRef<View>(null); // TS2749: 'View' refers to a value, not a type
+ const ref = useRef<React.ComponentRef<typeof View>>(null);
ref.current?.measure(...);
- const inputRef = useRef<TextInput>(null); // TS2749: 'TextInput' refers to a value, not a type
+ const inputRef = useRef<React.ComponentRef<typeof TextInput>>(null);
inputRef.current?.focus();
// After — original patterns work as-is
const ref = useRef<View>(null); // View as a type = HostInstance
ref.current?.measure(...); // HostInstance has measure()
const inputRef = useRef<TextInput>(null); // TextInput as a type = TextInputInstance
inputRef.current?.focus(); // TextInputInstance has focus()
```
Changelog:
[General][Fixed] - Add companion instance type aliases for built-in components, preserving `useRef<Component>` patterns under the Strict TypeScript API
Differential Revision: D1036019231 parent d1cdce2 commit 778ae87
2 files changed
Lines changed: 42 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
25 | 38 | | |
26 | 39 | | |
| 40 | + | |
27 | 41 | | |
28 | 42 | | |
29 | 43 | | |
| 44 | + | |
30 | 45 | | |
31 | 46 | | |
32 | 47 | | |
33 | 48 | | |
34 | 49 | | |
35 | 50 | | |
| 51 | + | |
36 | 52 | | |
37 | 53 | | |
38 | 54 | | |
| |||
56 | 72 | | |
57 | 73 | | |
58 | 74 | | |
| 75 | + | |
59 | 76 | | |
| 77 | + | |
60 | 78 | | |
61 | 79 | | |
62 | 80 | | |
| 81 | + | |
63 | 82 | | |
64 | 83 | | |
65 | 84 | | |
| 85 | + | |
66 | 86 | | |
67 | 87 | | |
68 | 88 | | |
| |||
74 | 94 | | |
75 | 95 | | |
76 | 96 | | |
| 97 | + | |
77 | 98 | | |
78 | 99 | | |
79 | 100 | | |
80 | 101 | | |
81 | 102 | | |
82 | 103 | | |
83 | 104 | | |
| 105 | + | |
84 | 106 | | |
85 | 107 | | |
86 | 108 | | |
| 109 | + | |
87 | 110 | | |
88 | 111 | | |
89 | 112 | | |
90 | 113 | | |
91 | 114 | | |
92 | 115 | | |
93 | 116 | | |
| 117 | + | |
94 | 118 | | |
95 | 119 | | |
| 120 | + | |
96 | 121 | | |
97 | 122 | | |
98 | 123 | | |
| |||
103 | 128 | | |
104 | 129 | | |
105 | 130 | | |
| 131 | + | |
106 | 132 | | |
107 | 133 | | |
108 | 134 | | |
| |||
118 | 144 | | |
119 | 145 | | |
120 | 146 | | |
| 147 | + | |
121 | 148 | | |
122 | 149 | | |
123 | 150 | | |
124 | 151 | | |
125 | 152 | | |
126 | 153 | | |
| 154 | + | |
127 | 155 | | |
128 | 156 | | |
129 | 157 | | |
| 158 | + | |
130 | 159 | | |
131 | 160 | | |
132 | 161 | | |
| |||
151 | 180 | | |
152 | 181 | | |
153 | 182 | | |
| 183 | + | |
154 | 184 | | |
155 | 185 | | |
156 | 186 | | |
157 | 187 | | |
158 | 188 | | |
| 189 | + | |
159 | 190 | | |
160 | 191 | | |
161 | 192 | | |
| 193 | + | |
162 | 194 | | |
163 | 195 | | |
164 | 196 | | |
| 197 | + | |
165 | 198 | | |
166 | 199 | | |
167 | 200 | | |
| 201 | + | |
168 | 202 | | |
169 | 203 | | |
170 | 204 | | |
| |||
182 | 216 | | |
183 | 217 | | |
184 | 218 | | |
| 219 | + | |
185 | 220 | | |
186 | 221 | | |
187 | 222 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
53 | 59 | | |
54 | | - | |
| 60 | + | |
55 | 61 | | |
56 | 62 | | |
57 | 63 | | |
| |||
0 commit comments