compiler: Handle TSNonNullAssertion expressions (#29218)

## Summary

We ran React compiler against part of our codebase and collected
compiler errors. One of the more common non-actionable errors is caused
by usage of the `!` TypeScript non-null assertion operation:

```
(BuildHIR::lowerExpression) Handle TSNonNullExpression expressions
```

It seems like React Compiler _should_ be able to support this by just
ignoring the syntax and using the underlying expression. I'm sure a lot
of our non-null assertion usage should not exist and I understand if
React Compiler does not want to support this syntax. It wasn't obvious
to me if this omission was intentional or if there are future plans to
use `TSNonNullExpression` as part of the compiler's analysis. If there
are no future plans it seems like just ignoring it should be fine.

## How did you test this change?

```sh
❯ yarn snap --filter
yarn run v1.17.3
$ yarn workspace babel-plugin-react-compiler run snap --filter
$ node ../snap/dist/main.js --filter
 PASS  non-null-assertion
1 Tests, 1 Passed, 0 Failed
```
This commit is contained in:
Henry Q. Dineen
2024-05-22 23:42:06 +01:00
committed by GitHub
parent f994737d14
commit 4c2e457c7c
3 changed files with 65 additions and 0 deletions
@@ -2407,6 +2407,10 @@ function lowerExpression(
loc: expr.node.loc ?? GeneratedSource,
};
}
case "TSNonNullExpression": {
let expr = exprPath as NodePath<t.TSNonNullExpression>;
return lowerExpression(builder, expr.get("expression"));
}
default: {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
@@ -0,0 +1,49 @@
## Input
```javascript
interface ComponentProps {
name?: string;
}
function Component(props: ComponentProps) {
return props.name!.toUpperCase();
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ name: "Alice" }],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
interface ComponentProps {
name?: string;
}
function Component(props) {
const $ = _c(2);
let t0;
if ($[0] !== props.name) {
t0 = props.name.toUpperCase();
$[0] = props.name;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ name: "Alice" }],
};
```
### Eval output
(kind: ok) "ALICE"
@@ -0,0 +1,12 @@
interface ComponentProps {
name?: string;
}
function Component(props: ComponentProps) {
return props.name!.toUpperCase();
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ name: "Alice" }],
};