Skip to content
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 19] prop-types removal alternative / console component trace #28992

Open
oliviertassinari opened this issue May 4, 2024 · 23 comments
Open
Labels

Comments

@oliviertassinari
Copy link
Contributor

oliviertassinari commented May 4, 2024

Summary

The state of .propTypes is a bit unclear. I see:

  1. https://react.dev/blog/2024/04/25/react-19 doesn't mention their deprecation but https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-proptypes-and-defaultprops does. Should the two pages by synced?
  2. https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-proptypes-and-defaultprops says:
image

But it looks inaccurate, I would expect it says that React.PropTypes were deprecated from the source linked.
SCR-20240504-buph
Source

  1. The migration guides encourage to migrate to "TypeScript or another type-checking solution", but TypeScript has a limited type coverage. For instance, it doesn't support integers. We rely on this e.g. (not the most convincing example, though, you can check Material UI codebase to see other examples, like deprecated props, incompatible props combinations)
Autocomplete.propTypes = {
  /**
   * The maximum number of tags that will be visible when not focused.
   * Set `-1` to disable the limit.
   * @default -1
   */
  limitTags: integerPropType,

https://github.com/mui/material-ui/blob/2827bacf567fc95ef147d543316ffe688896db90/packages/mui-material/src/Autocomplete/Autocomplete.js#L985-L990

So to replace this, it seems that the closest alternative is to do something like this:

function DemoComponent(props) {
  if (process.env.NODE_ENV !== "production") {
    if (typeof props.bar !== "string") {
      console.error(
        `Warning: Failed prop type: Invalid prop \`bar\` of type \`number\` supplied to \`DemoComponent\`, expected \`string\`.`
      );
    }
  }

  return null;
}

Unfortunately, it's missing the component trace.

Before: https://codesandbox.io/p/sandbox/mystifying-mcclintock-mf7r5m?file=%2Fsrc%2FDemo.js%3A16%2C1

SCR-20240504-oepf

After: https://codesandbox.io/p/sandbox/agitated-orla-8kj8rh?file=%2Fsrc%2Findex.js

SCR-20240504-oehu

It seems much harder to figure out where console logs come from. So while https://react.dev/blog/2024/04/25/react-19#diffs-for-hydration-errors is a great step forward, this one feels like a step backward. Is there an alternative to it?

There is a function in https://github.com/facebook/prop-types/blob/1c9c6311c1fb8778bffc7a1ca70c273ee8a8654d/checkPropTypes.js#L20 but it doesn't log the component trace either. This function was recommended in #28328.

@cherniavskii
Copy link
Contributor

Unfortunately, it's missing the component trace.

React is missing a public API for logging component stack trace.
The only way I managed to get the stack trace is this:

const getStackTrace = () => {
  let stack = '';
  const ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
  if (ReactSharedInternals != null) {
    const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
    const stackAddendum = ReactDebugCurrentFrame.getStackAddendum();
    if (stackAddendum !== '') {
      stack = stackAddendum;
    }
  }
  return stack;
}

The problems with this solution:

  • It uses internal API that differs across the major React versions
  • I would rather keep my current job 😅

Does the React team consider adding public API for this?

Alternatively, we can create a community package that would encapsulate the internal API access and provide a cross-version method for getting the stack trace.

@rickhanlonii
Copy link
Member

There are two separate issues here: PropTypes deprecation, and component stacks for console.error. The PropTypes concerns are understandable, but we're not adding support back to them. The blog posts are separate because one announces the features in 19, and the other the breaking/notable changes:

In our React 19 Beta Upgrade Guide, we shared step-by-step instructions for upgrading your app to React 19 Beta. In this post, we’ll give an overview of the new features in React 19, and how you can adopt them.

The component stack changes seem concerning, they seem to work for me in the CodeSandbox you linked:

Screenshot 2024-05-09 at 8 38 07 PM

@oliviertassinari
Copy link
Contributor Author

oliviertassinari commented May 10, 2024

they seem to work for me in the CodeSandbox you linked

@rickhanlonii the console component trace doesn't work when opening the codesandbox link standalone. It doesn't work on Vite either. I haven't tested Next.js but I don't recall seeing it work their either.

@Janpot
Copy link

Janpot commented May 10, 2024

Doesn't work in Next.js neither for me. I suppose normally the react devtools extension should kick in?

@cherniavskii
Copy link
Contributor

There are two separate issues here: PropTypes deprecation, and component stacks for console.error.

Correct! I mentioned the component stacks in this issue because we need them for props validation errors that would replace propTypes for us.

@jbt
Copy link

jbt commented Jun 5, 2024

I just stumbled on this issue while catching up on React 19 changes - specifically around the removal of propTypes checking, I'm concerned the documentation could have been clearer.

What's caught me off guard is that "Importing prop type checkers with React.PropTypes" and "actual checking of types defined with .propTypes" are two completely separate things, and only the former was ever actually documented & deprecated in 15.5.0, so it's a bit revisionist to say that proptypes themselves have been deprecated for that long.

As far as I can see there was no public discussion or proposal for the removal of actual prop type checking - and while I guess technically it's not a breaking change so it's not strictly necessary to put in deprecation warnings as with e.g. defaultProps, it's nonetheless caught me by surprise. I guess the ship has sailed now but I certainly would have welcomed the opportunity to contribute to any discussion when it was being considered.

@oliviertassinari
Copy link
Contributor Author

oliviertassinari commented Jul 22, 2024

Data from https://2023.stateofjs.com/en-US/usage/

SCR-20240722-nhza

You can conclude that:

  • 70% of the code written is in TypeScript (9.33 * 0+5.6 * 0.13+4.22 * 0.25+2.26 * 0.38+5.99 * 0.5+3.16 * 0.63+10.76 * 0.75+26.47 * 0.88+32.22 * 1) (up from 50% in 2022 https://2022.stateofjs.com/en-US/usage/#js_ts_balance)
  • 30% of the code written is in JavaScript (9.33 * 1+5.6 * 0.88+4.22 * 0.75+2.26 * 0.63+5.99 * 0.5+3.16 * 0.38+10.76 * 0.25+26.47 * 0.13+32.22 * 0)

We might be looking at 30% of the user base with no more types. It will be interesting to see what 2024 looks like. If this grows from 70% to 90%, it should be all fine.

Then, it's really only about the problems listed above with not having propTypes when writing TypeScript:

  • no React component trace with console.error()/console.warn()
  • no coverage for more specific types
  • no primitives for warning deduplication in render components

@ericfortis
Copy link

ericfortis commented Jul 28, 2024

Could anyone help me understand how to override class components for adding the type-value checks. That is, there is no React.Component.prototype.render.

So we can't simply:

import checkPropTypes from 'prop-types/checkPropTypes'

const oldRender = React.Component.prototype.render
React.Component.prototype.render = function () {
  checkPropTypes(this.propTypes, props, 'prop', this.name)
  oldRender()
}

Or any other approach. Thanks


As @oliviertassinari mentioned, I also check the values (not only the data type).
Also, as @jbt said, this deprecation caught me by surprised as well.

Copy link

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

@github-actions github-actions bot added the Resolution: Stale Automatically closed due to inactivity label Oct 27, 2024
@oliviertassinari

This comment was marked as resolved.

@github-actions github-actions bot removed the Resolution: Stale Automatically closed due to inactivity label Oct 27, 2024
@maa-wtag
Copy link

maa-wtag commented Nov 2, 2024

Bump

@dimitrisnl
Copy link

bump

@eps1lon
Copy link
Collaborator

eps1lon commented Nov 19, 2024

For those bumping: Are the component stacks still not showing up when React DevTools is attached?

@ericfortis
Copy link

ericfortis commented Nov 20, 2024

Looks like they are working in 19.0.0-rc.1

import React from 'react'
import { checkPropTypes } from 'prop-types'

Object.assign(React.Component.prototype, {
  checkProps() {
    checkPropTypes(this.constructor.propTypes, this.props, 'prop', this.constructor.name)
  }
})
class Card extends Component {
  render() {
    this.checkProps()
    return null
  }
}

Card.propTypes = {
  PN_card: PropTypes.object.isRequired
}
class App extends Component {
  render() {
    return React.createElement(Card, { PN_card: 1 })
  }
}
stack-traces-working

@eps1lon
Copy link
Collaborator

eps1lon commented Nov 20, 2024

That's not a component stack. Can you link a repro where this is not working? Preferably https://react.new.

@ericfortis
Copy link

Same code but with React DevTools installed:

with-react-devtools

@mqklin
Copy link

mqklin commented Dec 6, 2024

Is there a way to monkey-patch React lib, or using some babel-loader to continue using prop-types? Because currently there is no chance I can switch to TypeScript.

@adcorduneanu
Copy link

This decision seems like a significant step toward alienating a substantial portion of the React ecosystem. I’m not sure how or why it was determined that React should prioritize TypeScript (TS) while effectively sidelining JavaScript (JS), but this approach seems disconnected from the realities of the field.

Many existing projects, some with hundreds of thousands of lines of JS code, lack the resources or practical reasons to migrate to TS. For these teams, the benefits of such a transition are far from compelling.

While support for functional components via ES6 default objects may still exist, it doesn't provide the same level of type constraints that were invaluable for both prototyping and runtime validation. Losing this flexibility makes React less accessible and, frankly, less attractive for many real-world use cases.

This kind of "enhancement" feels more like a step backward. It risks undermining React's inclusivity and practicality, which could mark the end of its dominance in the ecosystem.

@sergei-startsev
Copy link
Contributor

For those looking for alternatives and not feeling comfortable moving all code to TS, it might be useful to consider migrating PropTypes to JSDoc with TS type checking (checkJs:true)

@oliviertassinari
Copy link
Contributor Author

oliviertassinari commented Jan 28, 2025

@sergei-startsev but the point of this issue for me is that static type checking is not covering as much ground as runtime type checking. Both are complementary, the best DX is using as much static type checking as possible, and fill the gaps with runtime type checking.

@sergei-startsev
Copy link
Contributor

@oliviertassinari It's clear that static analysis won't replace runtime checks. On the other hand, runtime warnings are often overlooked during development and you wouldn't want these checks in production, so maybe it's overrated from DX perspective.

@oliviertassinari
Copy link
Contributor Author

oliviertassinari commented Jan 30, 2025

I wish microsoft/TypeScript#49433 would be fixed. Without it, runtime warnings feel much better for deprecations.

@Domain314
Copy link

Data from https://2023.stateofjs.com/en-US/usage/
SCR-20240722-nhza

You can conclude that:

* 70% of the code written is in TypeScript (9.33 * 0+5.6 * 0.13+4.22 * 0.25+2.26 * 0.38+5.99 * 0.5+3.16 * 0.63+10.76 * 0.75+26.47 * 0.88+32.22 * 1) (up from 50% in 2022 https://2022.stateofjs.com/en-US/usage/#js_ts_balance)

* 30% of the code written is in JavaScript (9.33 * 1+5.6 * 0.88+4.22 * 0.75+2.26 * 0.63+5.99 * 0.5+3.16 * 0.38+10.76 * 0.25+26.47 * 0.13+32.22 * 0)

We might be looking at 30% of the user base with no more types. It will be interesting to see what 2024 looks like. If this grows from 70% to 90%, it should be all fine.

Then, it's really only about the problems listed above with not having propTypes when writing TypeScript:

* no React component trace with console.error()/console.warn()

* no coverage for more specific types

* no primitives for warning deduplication in render components

The data you linked is from 2022 https://2022.stateofjs.com/en-US/usage/#js_ts_balance
Here from 2024: https://2024.stateofjs.com/en-US/usage/#js_ts_balance

As you can see, nothing has changed for js.

Also it says "time spent writing JS/TS". not actual lines of codes. One could argue that writing JS (especially when prototyping) is way faster than in TS and produces more functional lines of code in x time spent.

I hope the decision to deprecate silently an npm package with nearly 5mio weekly downloads wasn't made on optimistic assumptions like your TS-forecast for 2024 "grows from 70 to 90%".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests