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: Make value returned by useState Readonly #64099

Closed
wants to merge 2 commits into from
Closed

react: Make value returned by useState Readonly #64099

wants to merge 2 commits into from

Conversation

SpLouk
Copy link

@SpLouk SpLouk commented Jan 26, 2023

Please fill in this template.

  • Use a meaningful title for the pull request. Include the name of the package modified.
  • Test the change in your own code. (Compile and run.)
  • Add or edit tests to reflect the change.
    • Not sure what to add as a test for this; this change is intended to make mutation of state impossible
  • Follow the advice from the readme.
  • Avoid common mistakes.
  • Run npm test <package to test>.

Select one of these and delete the others:

If changing an existing definition:

  • Provide a URL to documentation or source code which provides context for the suggested changes: <>
  • If this PR brings the type definitions up to date with a new version of the JS library, update the version number in the header.

State is immutable, so the return value of useState should be wrapped in the DeepReadonly utility type which can prevent accidental mutation.

https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts#L396

This will prevent accidental mutation of state. E.g.

const [arr, setArr] = useState(['a', 'b']);
arr.push('c')

@typescript-bot
Copy link
Contributor

typescript-bot commented Jan 26, 2023

@SpLouk Thank you for submitting this PR! I see this is your first time submitting to DefinitelyTyped 👋 — I'm the local bot who will help you through the process of getting things through.

This is a live comment which I will keep updated.

1 package in this PR

Code Reviews

This PR can be merged once it's reviewed.

You can test the changes of this PR in the Playground.

Status

  • ✅ No merge conflicts
  • ✅ Continuous integration tests have passed
  • 🕐 Most recent commit is approved by type definition owners or DT maintainers

Once every item on this list is checked, I'll ask you for permission to merge and publish the changes.


Diagnostic Information: What the bot saw about this PR
{
  "type": "info",
  "now": "-",
  "pr_number": 64099,
  "author": "SpLouk",
  "headCommitOid": "4665ec5e7744a6fc5d57bc0839b37a29811813cd",
  "mergeBaseOid": "7a09beca6be782271dd738e86e33c0a460539916",
  "lastPushDate": "2023-01-26T19:40:24.000Z",
  "lastActivityDate": "2023-01-30T21:08:25.000Z",
  "maintainerBlessed": "Waiting for Code Reviews",
  "hasMergeConflict": false,
  "isFirstContribution": true,
  "tooManyFiles": false,
  "hugeChange": false,
  "popularityLevel": "Critical",
  "pkgInfo": [
    {
      "name": "react",
      "kind": "edit",
      "files": [
        {
          "path": "types/react/package.json",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/react/v17/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "johnnyreilly",
        "bbenezech",
        "pzavolinsky",
        "ericanderson",
        "DovydasNavickas",
        "theruther4d",
        "guilhermehubner",
        "ferdaber",
        "jrakotoharisoa",
        "pascaloliv",
        "hotell",
        "franklixuefei",
        "Jessidhia",
        "saranshkataria",
        "lukyth",
        "eps1lon",
        "zieka",
        "dancerphil",
        "dimitropoulos",
        "disjukr",
        "vhfmag",
        "hellatan",
        "priyanshurav",
        "Semigradsky"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Critical"
    }
  ],
  "reviews": [],
  "mainBotCommentID": 1405524743,
  "ciResult": "pass"
}

@typescript-bot typescript-bot added Critical package Untested Change This PR does not touch tests labels Jan 26, 2023
@typescript-bot typescript-bot added this to Waiting for Code Reviews in New Pull Request Status Board Jan 26, 2023
@typescript-bot
Copy link
Contributor

@Semigradsky
Copy link
Contributor

I like this suggestion, but it will break a lot of existing code.

Copy link
Collaborator

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this suggestion, but it will break a lot of existing code.

Yeah I can see that. Just had a case today were a component library was expecting a mutable array (which is the default in TypeScript). In those cases, TypeScript would now throw.

Could you test this on some small/medium+ sized repositories to check how many new issues we create with this change?

@@ -918,15 +919,15 @@ declare namespace React {
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#usestate
*/
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S>(initialState: S | (() => S)): [DeepReadonly<S>, Dispatch<SetStateAction<S>>];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a Readonly here suffice for the majority of use cases? I'm mainly concerned about perf here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think DeepReadonly would be preferred to prevent mutating nested members of an object.

@psalv
Copy link

psalv commented Jan 26, 2023

I like this suggestion, but it will break a lot of existing code.

It's arguable this code has a high chance of being broken already, they just don't know about it

@DangerBotOSS
Copy link

Inspecting the JavaScript source for this package found some properties that are not in the .d.ts files.
The check for missing properties isn't always right, so take this list as advice, not a requirement.

react (unpkg)

was missing the following properties:

  1. unstable_act

Generated by 🚫 dangerJS against 4665ec5

@typescript-bot typescript-bot moved this from Waiting for Code Reviews to Needs Maintainer Review in New Pull Request Status Board Jan 26, 2023
@sheetalkamat sheetalkamat moved this from Needs Maintainer Review to Waiting for Code Reviews in New Pull Request Status Board Jan 26, 2023
@eps1lon
Copy link
Collaborator

eps1lon commented Jan 26, 2023

It's arguable this code has a high chance of being broken already, they just don't know about it

Did you run this on some example codebases? What were patterns that it did reject, that we want to reject and what were patterns we don't necessarily want to reject (e.g. due to the ecosystem not having props as readonly in most cases)?

@SpLouk
Copy link
Author

SpLouk commented Jan 27, 2023

Yeah, so this will definitely be a breaking change. I didn't anticipate this but

const [str,...] = useState(['a', 'b'])

return <Child str={ str } /> // pass the state down to a child

Will cause a type error because Child is expecting a string [] not a readonly string[].

I ran our type checker in Faire's codebase locally and got about 20 type errors of this form in a ~100,000 line React/TS codebase. We don't use hooks everywhere yet so that might be a low number for a codebase of that size.

Now, in a perfect world, all arrays and objects passed as props should be readonly too, but that isn't the case in our codebase and I'm sure many others.

@eps1lon
Copy link
Collaborator

eps1lon commented Jan 28, 2023

Now, in a perfect world, all arrays and objects passed as props should be readonly too, but that isn't the case in our codebase and I'm sure many others.

Same for our design system at Klarna.

Did you catch any actual errors similar to the one explained in the PR description?

@SpLouk
Copy link
Author

SpLouk commented Jan 30, 2023

Did you catch any actual errors similar to the one explained in the PR description?

No, no instances of an object actually being mutated.

@SpLouk SpLouk closed this by deleting the head repository Jan 30, 2023
@typescript-bot typescript-bot removed this from Waiting for Code Reviews in New Pull Request Status Board Jan 30, 2023
@SpLouk
Copy link
Author

SpLouk commented Jan 30, 2023

Going to go with an internal solution here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Critical package Untested Change This PR does not touch tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants