ryanahamilton opened a new pull request, #71563:
URL: https://github.com/apache/airflow/pull/71563
`React.FC` adds nothing over annotating the props parameter directly, and
the UI packages were split between the two styles — 13 components used
`React.FC` while 540+ others annotated the parameter. The same split showed up
in type references, where `React.ReactNode` / `React.ReactElement` sat
alongside the dominant `import { type ReactNode } from "react"` style.
Every React package here compiles with the automatic JSX runtime (`"jsx":
"react-jsx"`), so no file needs a `React` import at all — the namespace
survived only as habit. This removes both patterns and adds ESLint rules so
they cannot creep back in.
### Cleanup
| Package | `React.FC` | Namespaced type refs | Value refs |
|---|---|---|---|
| `airflow-core/src/airflow/ui` | 13 | 79 | 30 |
| simple auth manager UI | 0 | 6 | 0 |
| edge3 plugin UI | 0 | 9 | 3 |
| react plugin template | 0 | 0 | 0 |
Three props types gained `readonly`: `react/prefer-read-only-props` is
already at `ERROR` but cannot see through `React.FC<Props>`, so it only starts
applying once the type moves onto the parameter.
### Enforcement
Two rules, because neither alone is sufficient:
- **`@typescript-eslint/no-restricted-imports`** bans the `React`
default/namespace import. With the import gone, TypeScript also reports
`TS2686` on any leftover value-position `React.x`.
- **`no-restricted-syntax`** bans namespaced *type* references. This one is
load-bearing: `@types/react` declares `export as namespace React`, so
`React.FC<Props>` type-checks with **no import at all** — 4 of the 13
`React.FC` files did exactly that, and the import ban alone would have missed
them.
The `FC` selector is deliberately narrow — it fires only when `FC` types a
variable whose initializer is an arrow function, i.e. a component *definition*.
Annotating a component *value* stays legal, which two existing usages rely on
(`components/ui/ButtonGroupToggle.tsx`, `pages/ReactPlugin.tsx`).
### Notes for reviewers
- **`src/main.tsx` is the one exemption**, via `eslint-disable` with a
comment. It republishes the host's React on `globalThis` for plugin bundles,
which are built as UMD against a `React` global (`rollup output.globals: {
react: "React" }`). Changing the import form would change which object plugins
receive, so that file is a comment-only diff with no runtime change.
- The rules caught two bare `FC` component definitions that a text search
for `React.` could not see, in the edge3 and plugin-template `main.tsx`. Fixing
the template stops new plugin UIs being scaffolded with the pattern.
- No newsfragment: internal refactor with no user-visible behaviour change.
### Verification
ESLint reports 0 errors on both airflow-core UIs and `tsc` is clean; the 141
remaining warnings are pre-existing `react-refresh/only-export-components` ones
in files this PR does not touch. 854 unit tests pass. `prek run --stage
pre-commit` passes with no file modifications.
edge3 needed a workaround to verify: its ESLint currently cannot start at
all (a `"ajv@<8.18.0"` override in its `package.json` bumps ESLint's own
`ajv@6` to `ajv@8`, and ESLint 10 needs ajv 6's `json-schema-draft-04.json`),
and its `ts-compile-lint-edge-ui` prek hook passes vacuously because
`scripts/ci/prek/ts_compile_lint_edge.py` resolves its filter path against the
repo root while the nested config passes paths relative to `providers/edge3/`,
so it filters every file out. Both reproduce on a clean `main` and are
unrelated to this PR; I verified edge3 by temporarily pointing its ESLint at a
working ajv and running its real config — **13 violations of the new rules
before the cleanup, 0 after**, with every other rule count identical. Its three
pre-existing `tsc` errors are byte-identical before and after. Happy to file
those separately.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes — Claude Code (Opus 5)
Generated-by: Claude Code (Opus 5) following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]