mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[compiler] Type ref prop as a ref
Adds a shape type for component props, which has one defined property: "ref". This means that if the ref property exists, we can type usage of `props.ref` (or via destructuring) the same as the result of `useRef()` and infer downstream usage similarly.
ghstack-source-id: 76cd07c5df
Pull Request resolved: https://github.com/facebook/react/pull/29834
This commit is contained in:
@@ -188,6 +188,7 @@ export type ObjectShape = {
|
||||
* the inferred types for [] and {}.
|
||||
*/
|
||||
export type ShapeRegistry = Map<string, ObjectShape>;
|
||||
export const BuiltInPropsId = "BuiltInProps";
|
||||
export const BuiltInArrayId = "BuiltInArray";
|
||||
export const BuiltInFunctionId = "BuiltInFunction";
|
||||
export const BuiltInJsxId = "BuiltInJsx";
|
||||
@@ -207,6 +208,11 @@ export const BuiltInDispatchId = "BuiltInDispatch";
|
||||
// ShapeRegistry with default definitions for built-ins.
|
||||
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
|
||||
|
||||
// If the `ref` prop exists, it has the ref type
|
||||
addObject(BUILTIN_SHAPES, BuiltInPropsId, [
|
||||
["ref", { kind: "Object", shapeId: BuiltInUseRefId }],
|
||||
]);
|
||||
|
||||
/* Built-in array shape */
|
||||
addObject(BUILTIN_SHAPES, BuiltInArrayId, [
|
||||
[
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
BuiltInFunctionId,
|
||||
BuiltInJsxId,
|
||||
BuiltInObjectId,
|
||||
BuiltInPropsId,
|
||||
BuiltInUseRefId,
|
||||
} from "../HIR/ObjectShape";
|
||||
import { eachInstructionLValue, eachInstructionOperand } from "../HIR/visitors";
|
||||
@@ -101,7 +102,13 @@ function* generate(
|
||||
func: HIRFunction
|
||||
): Generator<TypeEquation, void, undefined> {
|
||||
if (func.env.fnType === "Component") {
|
||||
const [_, ref] = func.params;
|
||||
const [props, ref] = func.params;
|
||||
if (props && props.kind === "Identifier") {
|
||||
yield equation(props.identifier.type, {
|
||||
kind: "Object",
|
||||
shapeId: BuiltInPropsId,
|
||||
});
|
||||
}
|
||||
if (ref && ref.kind === "Identifier") {
|
||||
yield equation(ref.identifier.type, {
|
||||
kind: "Object",
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component({ ref }) {
|
||||
const value = ref.current;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
2 | function Component({ ref }) {
|
||||
3 | const value = ref.current;
|
||||
> 4 | return <div>{value}</div>;
|
||||
| ^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $17:TObject<BuiltInRefValue> (4:4)
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component({ ref }) {
|
||||
const value = ref.current;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component(props) {
|
||||
const value = props.ref.current;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
2 | function Component(props) {
|
||||
3 | const value = props.ref.current;
|
||||
> 4 | return <div>{value}</div>;
|
||||
| ^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $15:TObject<BuiltInRefValue> (4:4)
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component(props) {
|
||||
const value = props.ref.current;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component(props) {
|
||||
const ref = props.ref;
|
||||
ref.current = true;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
2 | function Component(props) {
|
||||
3 | const ref = props.ref;
|
||||
> 4 | ref.current = true;
|
||||
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
||||
5 | return <div>{value}</div>;
|
||||
6 | }
|
||||
7 |
|
||||
```
|
||||
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// @validateRefAccessDuringRender @compilationMode(infer)
|
||||
function Component(props) {
|
||||
const ref = props.ref;
|
||||
ref.current = true;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
Reference in New Issue
Block a user