-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[react] Types for React 19 #69022
Draft
eps1lon
wants to merge
56
commits into
DefinitelyTyped:master
Choose a base branch
from
eps1lon:react/19
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
[react] Types for React 19 #69022
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eps1lon
added
pkg: react@19.0.x
Discussions related to the release of React 19.0
and removed
pkg: react@19.0.0
labels
Mar 17, 2024
eps1lon
force-pushed
the
react/19
branch
15 times, most recently
from
March 23, 2024 20:10
6f5e24f
to
bd58fbf
Compare
eps1lon
force-pushed
the
react/19
branch
4 times, most recently
from
March 26, 2024 20:20
47920ab
to
51e726f
Compare
This was referenced Mar 26, 2024
There's little harm in keeping them around for now. `defaultProps` are still `never` since assuming these are applied would cause issues in production.
This is somewhat bad because hnrs is by definition not compatible since it treats removed statics as react statics even though they no longer are. But then the constraints weren't necessary in the first place and more of a "this is what you should pass in here".
This was referenced May 24, 2024
This was referenced May 30, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Changelog
Table of Contents
useReducer
ReactElement
propTypes
anddefaultProps
staticsIn recent years, the API surface of
@types/react
has gotten larger than we'd like.This makes working with React and TypeScript unnecessarily tricky.
So, we're taking this opportunity to make some small breaking changes to our types, deprecating some and removing others.
We've wanted to make the migration easier - most can be automated with codemods.
Check out the migration guide below for more information.
The runtime changes are far more important since they directly affect the end user of your application.
They'll be detailed in React's release notes.
Try It Out (before React 19.0.0 is released)
The
@types/*
packages don't support pre-releases.Instead, you'll have to alias React types packages to other packages.
Modern package managers support this via
resolutions
oroverrides
.Yarn and PNPM:
NPM:
The following types packages have alphas under different packages:
@types/react
->types-react
@types/react-dom
->types-react-dom
@types/react-is
->types-react-is
@types/react-test-renderer
->types-react-test-renderer
@types/scheduler
->types-scheduler
@types/use-sync-external-store
->types-use-sync-external-store
Migrating
While we have included some breaking changes, most of them can be resolved with codemods to keep manual work to a minimum.
Quick Explanation
Full Explanation
Almost all of the
@types/*
packages are already compatible with React 19 types unless they specifically rely on React 18. Therefore it is advised to upgrade all React-related@types/*
packages first.Apply the
preset-19
codemod fromtypes-react-codemod
in its default configuration vianpx types-react-codemod@latest preset-19 ./path-to-your-react-ts-files
.In our experience, this covers most breaking changes.
The largest block of remaining type issues relate to props of React elements now defaulting to
unknown
instead ofany
.If you're focus is on migration instead of soundness, you can use the
react-element-default-any-props
to resolve a large portion of the breaking changes related toReactElement
.However, the codemod can't cover every pattern.
You probably have to manually adjust the lines relying on
any
inelement.props
either by additional runtime checking or manual casts toany
.You can check out the example migrations done on libraries e.g. MUI or apps e.g. Bluesky to get an idea of the possible patterns.
Breaking changes
This section focuses on breaking changes for the React types.
Some types have been removed, some type parameters have been changed, and
useRef
has been simplified.Removed deprecated TypeScript types
Some of the removed have types been moved to more relevant packages, like
Validator
moving toPropTypes
.Others are no longer needed to describe React's behavior.
Removing them means one less thing to learn.
Codemoddable
ReactChild
deprecated-react-child
React.ReactElement | number | string
ReactFragment
deprecated-react-fragment
Iterable<React.ReactNode>
ReactNodeArray
deprecated-react-node-array
ReadonlyArray<React.ReactNode>
ReactText
deprecated-react-text
number | string
Requireable
deprecated-prop-types-types
Requireable
fromprop-types
ValidationMap
deprecated-prop-types-types
ValidationMap
fromprop-types
Validator
deprecated-prop-types-types
Validator
fromprop-types
VoidFunctionComponent
deprecated-void-function-component
FunctionComponent
VFC
deprecated-void-function-component
FC
WeakValidationMap
deprecated-prop-types-types
WeakValidationMap
fromprop-types
Not Codemoddable
During our example migrations, these types were not used at all.
If you feel a codemod is missing, it can be tracked in the list of missing React 19 codemods.
ClassicComponentClass
ClassicComponentClass
fromcreate-react-class
ClassicComponent
ClassicComponent
fromcreate-react-class
ClassicElement<Props>
ClassicElement<Props, InstanceType<T>>
fromcreate-react-class
ComponentSpec
ComponentSpec
from thecreate-react-class
packageMixin
Mixin
from thecreate-react-class
packageReactChildren
typeof React.Children
ReactHTML
ReactHTML
fromreact-dom-factories
or, if you usedkeyof ReactHTML
, useHTMLElementType
insteadReactSVG
ReactSVG
fromreact-dom-factories
or, if you usedkeyof ReactSVG
, useSVGElementType
insteadSFCFactory
JSX Namespace
A long-time request is to remove the global
JSX
namespace from our types in favor ofReact.JSX
.This helps prevent pollution of global types which prevents conflicts between different UI libraries that leverage JSX.
This change is codemoddable with
scoped-jsx
.You'll now need to wrap module augmentation of the JSX namespace in `declare module "....":
The exact module specifier depends on the JSX runtime you specified in the
compilerOptions
of yourtsconfig.json
.For
"jsx": "react-jsx"
it would bereact/jsx-runtime
.For
"jsx": "react-jsxdev"
it would bereact/jsx-dev-runtime
.For
"jsx": "react"
and"jsx": "preserve"
it would bereact
.Changes to Type Parameters
useReducer
useReducer
now has improved type inference thanks to @mfp22.However, this required a breaking change where
useReducer
doesn't accept the full reducer type as a type parameter but instead either needs none (and rely on contextual typing) or needs both the state and action type.The new best practice is not to pass type arguments to
useReducer
.However, this may not work in edge cases where you can explicitly type the state and action, by passing in the
Action
in a tuple:If you define the reducer inline, we encourage to annotate the function parameters instead:
This, of course, is also what you'd also have to do if you move the reducer outside of the
useReducer
call:ReactElement
The
props
of React elements now default tounknown
instead ofany
if the element is typed asReactElement
. This does not affect you if you pass a type argument toReactElement
:But if you relied on the default, you now have to handle
unknown
:If you rely on this behavior, use the
react-element-default-any-props
codemod.You should only need it if you have a lot of legacy code relying on unsound access of element props.
Element introspection only exists as an escape hatch and you should make it explicit that your props access is unsound via an explicit
any
.Component types
Due to the removal of legacy context, forward ref render functions (e.g.
(props: P, ref: Ref<T>) => ReactNode
) will now be rejected by TypeScript if used as a component type.This was almost always a bug that needed fixing by wrapping the render function in
forwardRef
or removing the secondref
parameter.Ref cleanup
Due to the introduction of ref cleanup functions, returning anything else from a ref callback will now be rejected by TypeScript.
The fix is usually to stop using implicit returns e.g.
The original code returned the instance of the
HTMLDivElement
and TypeScript wouldn't know if this was supposed to be a cleanup function or if you didn't want to return a cleanup function.You can codemod this pattern with
no-implicit-ref-callback-return
propTypes
anddefaultProps
staticspropTypes
are now ignored by React.However, to ease migration, we just type
propTypes
asany
to ease migration in case these components are a bridge between typed and untyped components.If we'd remove
propTypes
entirely, a lot of assignments would cause TypeScript issues.The same does not apply to
defaultProps
on function components since not rejecting them during type-checking would cause actual issues at runtime.Please check out the changelog entry for the removal of
defaultProps
to learn how to migrate off ofdefaultProps
.Ref changes
A long-time complaint of how TypeScript and React work has been
useRef
.We've changed the types so that
useRef
now requires an argument.This significantly simplifies its type signature. It'll now behave more like
createContext
.This now also means that all refs are mutable.
You'll no longer hit the issue where you can't mutate a ref because you initialised it with
null
:MutableRef
is now deprecated in favor of a singleRefObject
type whichuseRef
will always return:useRef
still has a convenience overload foruseRef<T>(null)
that automatically returnsRefObject<T | null>
.To ease migration due to the required argument for
useRef
, a convenience overload foruseRef(undefined)
was added that automatically returnsRefObject<T | undefined>
.Check out [RFC] Make all refs mutable for prior discussions about this change.
Codemod
When you apply the
useRef-required-initial
codemod (part ofpreset-19
), alluseRef()
calls will be converted touseRef(undefined)
.Repo stuff, not the changelog
Thanks to @mattpocock for writing the changelog!
Closed issues
Closes #64451
Closes #64896
Closes #64772
Closes #64412
Closes #64920
Reviewer notes
For changes to React runtime APIs, please file them as issues to facebook/react instead. Keep the discussion focused on types.
For changelog review, please use eps1lon#35
CI failure related to "React 19 not found on NPM" is expected. All the other failures need to be gone. I'll extracted as many required changes to other packages as possible to earlier PRs.
Maintainer notes
Before merge:
Create React 18 fork with https://github.com/eps1lon/react-types-tools/blob/main/createReact18TypesFork.sh
Backport changes to ts5.0 fork with