{"id":13837718,"url":"https://github.com/eps1lon/types-react-codemod","last_synced_at":"2025-04-12T06:15:38.172Z","repository":{"id":36972994,"uuid":"477374713","full_name":"eps1lon/types-react-codemod","owner":"eps1lon","description":"Collection of transforms for jscodeshift related to `@types/react`","archived":false,"fork":false,"pushed_at":"2025-04-08T14:35:20.000Z","size":735521,"stargazers_count":350,"open_issues_count":19,"forks_count":15,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T06:15:19.523Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eps1lon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["eps1lon"]}},"created_at":"2022-04-03T14:59:02.000Z","updated_at":"2025-04-07T10:23:26.000Z","dependencies_parsed_at":"2024-05-18T00:22:23.751Z","dependency_job_id":"15f74964-4579-4ec6-a3fb-afd10ce564ff","html_url":"https://github.com/eps1lon/types-react-codemod","commit_stats":{"total_commits":404,"total_committers":6,"mean_commits":67.33333333333333,"dds":0.2623762376237624,"last_synced_commit":"c4304e0ab9d8c5f47f31e2086266ab5d944594b3"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eps1lon%2Ftypes-react-codemod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eps1lon%2Ftypes-react-codemod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eps1lon%2Ftypes-react-codemod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eps1lon%2Ftypes-react-codemod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eps1lon","download_url":"https://codeload.github.com/eps1lon/types-react-codemod/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525138,"owners_count":21118619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T15:01:22.196Z","updated_at":"2025-04-12T06:15:38.125Z","avatar_url":"https://github.com/eps1lon.png","language":"JavaScript","readme":"# types-react-codemod\n\nCollection of transforms for [jscodeshift](https://github.com/facebook/jscodeshift) related to `@types/react`.\n\n## Getting started\n\nThe codemod helps to fix potential TypeScript compile errors when upgrading to `@types/react@^18.0.0`.\nHowever, we recommend to apply this codemod if you're using `@types/react@^17.0.30`.\n\n```bash\n$ npx types-react-codemod preset-18 ./src\n? Pick transforms to apply (Press \u003cspace\u003e to select, \u003ca\u003e to toggle all, \u003ci\u003e to invert selection, and \u003center\u003e to proce\ned)\n❯◯ context-any\n ◉ deprecated-react-type\n ◉ deprecated-sfc-element\n ◉ deprecated-sfc\n ◉ deprecated-stateless-component\n ◯ implicit-children\n ◯ useCallback-implicit-any\nAll done.\nResults:\n0 errors\n20 unmodified\n0 skipped\n3 ok\nTime elapsed: 0.229seconds\n```\n\n## Usage\n\n```bash\n$ npx types-react-codemod \u003ccodemod\u003e \u003cpaths...\u003e\n\nPositionals:\n  codemod  [string] [required] [choices: \"context-any\", \"deprecated-legacy-ref\",\n                        \"deprecated-prop-types-types\", \"deprecated-react-child\",\n                     \"deprecated-react-fragment\", \"deprecated-react-node-array\",\n     \"deprecated-react-text\", \"deprecated-react-type\", \"deprecated-sfc-element\",\n                             \"deprecated-sfc\", \"deprecated-stateless-component\",\n                      \"deprecated-void-function-component\", \"implicit-children\",\n                    \"no-implicit-ref-callback-return\", \"preset-18\", \"preset-19\",\n          \"react-element-default-any-props\", \"refobject-defaults\", \"scoped-jsx\",\n                          \"useCallback-implicit-any\", \"useRef-required-initial\"]\n  paths                                                      [string] [required]\n\nOptions:\n  --version         Show version number                                [boolean]\n  --help            Show help                                          [boolean]\n  --dry                                               [boolean] [default: false]\n  --ignore-pattern                      [string] [default: \"**/node_modules/**\"]\n  --yes             Automatically accepts all prompts. Useful when no user input\n                    is available or desired.          [boolean] [default: false]\n  --verbose                                           [boolean] [default: false]\n\nExamples:\n  types-react-codemod preset-18 ./          Ignores `node_modules` and `build`\n  --ignore-pattern                          folders\n  \"**/{node_modules,build}/**\"\n```\n\n## Available transforms\n\nThe transforms are meant to migrate old code.\nThe transformed code is not intended to be used as a pattern for new code.\n\nSome transforms change code they shouldn't actually change.\nFixing all of these requires a lot of implementation effort.\nWhen considering false-positives vs false-negatives, codemods opt for false-positives.\nThe reason being that a false-positive can be reverted easily (assuming you have the changed code in Version Control e.g. git) while a false-negative requires manual input.\n\n- `preset-18`\n  - `deprecated-react-type`\n  - `deprecated-sfc-element`\n  - `deprecated-sfc`\n  - `deprecated-stateless-component`\n  - `context-any`\n  - `implicit-children`\n  - `useCallback-implicit-any`\n- `preset-19`\n  - `deprecated-legacy-ref`\n  - `deprecated-prop-types-types`\n  - `deprecated-react-child`\n  - `deprecated-react-fragment`\n  - `deprecated-react-node-array`\n  - `deprecated-react-text`\n  - `deprecated-void-function-component`\n  - `no-implicit-ref-callback-return`\n  - `react-element-default-any-props`\n  - `refobject-defaults`\n  - `scoped-jsx`\n  - `useRef-required-initial`\n\n### `preset-18`\n\nThis codemod combines all codemods for React 18 types.\nYou can interactively pick the codemods included.\nBy default, the codemods that are definitely required to upgrade to `@types/react@^18.0.0` are selected.\nThe other codemods may or may not be required.\nYou should select all and audit the changed files regardless.\n\n### `context-any` (React 18)\n\n```diff\n class Component extends React.Component\u003cProps\u003e {\n+  context: any\n   render() {\n\t\t return this.context.someContextProperty;\n\t }\n }\n```\n\nYou should only apply this codemod to files where the type-checker complains about access of `unknown` in `this.context`.\nWe'll check for any occurence of `context` (case-sensitive) in a `React.Component` body (or `React.PureComponent`).\nIf we find any occurence of `context` we'll add `context: any` declaration to the class body.\n\n#### false-positive on `context` usage\n\nWe'll add `context: any` even if you write `const { context } = props`.\nThis simplifies the implementation tremendously and follows the overall rationale for false-positives: it can be reverted easily and at worst restores the behavior of React 17 typings.\n\n#### false-negative when inheriting from another component\n\nClass inheritance chains are not handled.\n\n```tsx\nclass A extends React.Component {}\n\nclass B extends A {\n\trender() {\n\t\t// will error since the transform does not add `context: any` to the declaration of `A` nor `B`.\n\t\t// It's up to you to decide whether `A` or `B` should have this declaration\n\t\treturn this.context.value;\n\t}\n}\n```\n\nWe'll also miss usage of `context` if it's accessed outside of the class body e.g.\n\n```tsx\nfunction getValue(that) {\n\treturn that.context.value;\n}\n\nclass A extends React.Component {\n\trender() {\n\t\treturn getValue(this);\n\t}\n}\n```\n\nThis doesn't really follow the general transform rationale of \"over-applying\" since at worst we restore React 17 behavior.\nI just think that most class components do not use `this.context` (or already have a type declaration) somewhere else.\n\n### All `deprecated-` transforms\n\n```diff\n-React.ReactType\n+React.ElementType\n-React.SFC\n+React.FC\n-React.StatelessComponent\n+React.FunctionComponent\n-React.SFCElement\n+React.FunctionComponentElement\n```\n\nThey simply rename identifiers with a specific name.\nIf you have a type with the same name from a different package, then the rename results in a false positive.\nFor example, `ink` also has a `StatelessComponent` but you don't need to rename that type since it's not deprecated.\n\n### `implicit-children` (React 18)\n\n```diff\n-React.FunctionComponent\u003cProps\u003e\n+React.FunctionComponent\u003cReact.PropsWithChildren\u003cProps\u003e\u003e\n-React.FunctionComponent\n+React.FunctionComponent\u003cReact.PropsWithChildren\u003cunknown\u003e\u003e\n```\n\nThis transform will wrap the props type of `React.FunctionComponent` (and `FC`, `ComponentType`, `SFC` and `StatelessComponent`) with `React.PropsWithChildren`.\nNote, that the transform assumes `React.PropsWithChildren` is available.\nWe can't add that import since `React.PropsWithChildren` can be available via `tsconfig.json`.\n\n#### `implicit-children` false-positive pattern A\n\nWe'll apply `React.PropsWithChildren` everytime.\nIf you have a component that doesn't actually take `children`, we'll not fix what removal of implicit children should've fixed.\n\nSimilarly, if your props already have `children` declared, `PropsWithChildren` will be redundant.\nRedundant `PropsWithChildren` are only problematic stylistically.\n\n#### `implicit-children` false-positive pattern B\n\n`MyFunctionComponent\u003cProps\u003e` where `MyFunctionComponent` comes from `import { FunctionComponent as MyFunctionComponent } from 'react'` will be ignored.\nIn other words, the transform will not wrap `Props` in `React.PropsWithChildren`.\nThe transform would need to implement scope tracking for this pattern to get fixed.\n\n### `useCallback-implicit-any` (React 18)\n\n```diff\n-React.useCallback((event) =\u003e {})\n+React.useCallback((event: any) =\u003e {})\n```\n\nThis transform should only be applied to files where TypeScript errors with \"Parameter '\\*' implicitly has an 'any' type.(7006)\" in `useCallback`.\n\n#### `useCallback-implicit-any` false-positive pattern A\n\nIf the callback param is inferrable by TypeScript we might apply `any` without need.\nIn the example below the type of `event` is inferrable and adding `any` essentially reduces type coverage.\nThis is why it's recommended to only apply `useCallback-implicit-any` to files that produce \"Parameter '\\*' implicitly has an 'any' type.(7006)\" when type-checking with `@types/react@^18.0.0`.\n\n```diff\ntype CreateCallback = () =\u003e (event: Event) =\u003e void;\n-const createCallback: CreateCallback = () =\u003e useCallback((event) =\u003e {}, [])\n+const createCallback: CreateCallback = () =\u003e useCallback((event: any) =\u003e {}, [])\n```\n\n### `preset-19`\n\nThis codemod combines all codemods for React 19 types.\nYou can interactively pick the codemods included.\nBy default, the codemods that are definitely required to upgrade to `@types/react@^19.0.0` are selected.\nThe other codemods may or may not be required.\nYou should select all and audit the changed files regardless.\n\n### `deprecated-prop-types-types` (React 19)\n\n```diff\n+import * as PropTypes from \"prop-types\";\n import * as React from \"react\";\n-declare const requireable: React.Requireable\u003cReact.ReactNode\u003e;\n+declare const requireable: PropTypes.Requireable\u003cReact.ReactNode\u003e;\n-declare const validator: React.Validator\u003cReact.ReactNode\u003e;\n+declare const requireable: PropTypes.Validator\u003cReact.ReactNode\u003e;\n-declare const validationMap: React.ValidationMap\u003c{}\u003e;\n+declare const requireable: PropTypes.ValidationMap\u003cReact.ReactNode\u003e;\n-declare const weakValidationMap: React.WeakValidationMap\u003c{}\u003e;\n+declare const requireable: PropTypes.WeakValidationMap\u003cReact.ReactNode\u003e;\n```\n\n### `deprecated-legacy-ref` (React 19)\n\n```diff\n import * as React from \"react\";\n interface Props {\n-  ref?: React.LegacyRef;\n+  ref?: React.Ref;\n }\n```\n\n#### `deprecated-legacy-ref false-negative pattern A\n\nImporting `LegacyRef` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { LegacyRef as MyLegacyRef } from \"react\";\ninterface Props {\n\t// not transformed\n\tref?: MyLegacyRef;\n}\n```\n\n### `deprecated-react-child` (React 19)\n\n```diff\n import * as React from \"react\";\n interface Props {\n-  label?: React.ReactChild;\n+  label?: React.ReactElement | number | string;\n }\n```\n\n#### `deprecated-react-child` false-negative pattern A\n\nImporting `ReactChild` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { ReactChild as MyReactChild } from \"react\";\ninterface Props {\n\t// not transformed\n\tlabel?: MyReactChild;\n}\n```\n\n### `deprecated-react-node-array` (React 19)\n\n```diff\n import * as React from \"react\";\n interface Props {\n-  children?: React.ReactNodeArray;\n+  children?: ReadonlyArray\u003cReact.ReactNode\u003e;\n }\n```\n\n#### `deprecated-react-node-array` false-negative pattern A\n\nImporting `ReactNodeArray` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { ReactNodeArray as MyReactNodeArray } from \"react\";\ninterface Props {\n\t// not transformed\n\tchildren?: MyReactNodeArray;\n}\n```\n\n### `deprecated-react-fragment` (React 19)\n\n```diff\n import * as React from \"react\";\n interface Props {\n-  children?: React.ReactFragment;\n+  children?: Iterable\u003cReact.ReactNode\u003e;\n }\n```\n\n#### `deprecated-react-fragment` false-negative pattern A\n\nImporting `ReactFragment` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { ReactFragment as MyReactFragment } from \"react\";\ninterface Props {\n\t// not transformed\n\tchildren?: MyReactFragment;\n}\n```\n\n### `deprecated-react-text` (React 19)\n\n```diff\n import * as React from \"react\";\n interface Props {\n-  label?: React.ReactText;\n+  label?: number | string;\n }\n```\n\n#### `deprecated-react-text` false-negative pattern A\n\nImporting `ReactText` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { ReactText as MyReactText } from \"react\";\ninterface Props {\n\t// not transformed\n\tlabel?: MyReactText;\n}\n```\n\n### `deprecated-void-function-component` (React 19)\n\nWARNING: Only apply to codebases using `@types/react@^18.0.0`.\nIn earlier versions of `@types/react` this codemod would change the typings.\n\n```diff\n import * as React from \"react\";\n-const Component: React.VFC = () =\u003e {}\n+const Component: React.FC = () =\u003e {}\n-const Component: React.VoidFunctionComponent = () =\u003e {}\n+const Component: React.FunctionComponent = () =\u003e {}\n```\n\n### `no-implicit-ref-callback-return` (React 19)\n\nOff by default in `preset-19`. Can be enabled when running `preset-19`.\n\nWARNING: Manually review changes in case you already used ref cleanups in Canary builds.\n\nEnsures you don't accidentally return anything from ref callbacks since the return value was always ignored.\nWith ref cleanups, this is no longer the case and flagged in types to avoid mistakes.\n\n```diff\n-\u003cdiv ref={current =\u003e (instance = current)} /\u003e\n+\u003cdiv ref={current =\u003e {instance = current}} /\u003e\n```\n\nThis only works for the `ref` prop.\nThe codemod will not apply to other props that take refs (e.g. `innerRef`).\n\n### `react-element-default-any-props` (React 19)\n\n\u003e [!CAUTION]\n\u003e This codemod is only meant as a migration helper for old code.\n\u003e The new default for props of `React.ReactElement` is `unknown` but a lot of existing code relied on `any`.\n\u003e The codemod should only be used if you have a lot of code relying on the old default.\n\u003e Typing out the expected shape of the props is recommended.\n\u003e It's also likely that manually fixing is sufficient.\n\u003e In [vercel/nextjs we only had to fix one file](https://github.com/eps1lon/next.js/pull/1/commits/97fcba326ef465d134862feb1990f875d360675e) while the codemod would've changed 15 files.\n\nOff by default in `preset-19`. Can be enabled when running `preset-19`.\n\nDefaults the props of a `React.ReactElement` value to `any` if it has the explicit type.\n\n```diff\n-declare const element: React.ReactElement\n+declare const element: React.ReactElement\u003cany\u003e\n```\n\nDoes not overwrite existing type parameters.\n\nThe codemod does not work when the a value has the `React.ReactElement` type from 3rd party dependencies e.g. in `const: element: React.ReactNode`, the element would still have `unknown` props.\n\nThe codemod also does not work on type narrowing e.g.\n\n```tsx\nif (React.isValidElement(node)) {\n\telement.props.foo;\n\t//            ^^^ Cannot access propertiy 'any' of `unknown`\n}\n```\n\nThe props would need to be cast to `any` (e.g. `(element.props as any).foo`) to preserve the old runtime behavior.\n\n### `refobject-defaults` (React 19)\n\n`RefObject` no longer makes `current` nullable by default\n\n```diff\n import * as React from \"react\";\n-const myRef: React.RefObject\u003cView\u003e\n+const myRef: React.RefObject\u003cView | null\u003e\n```\n\n#### `refobject-defaults` false-negative pattern A\n\nImporting `RefObject` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { RefObject as MyRefObject } from \"react\";\n\n// not transformed\nconst myRef: MyRefObject\u003cView\u003e;\n```\n\n### `scoped-jsx` (React 19)\n\nEnsures access to global JSX namespace is now scoped to React (see [DefinitelyTyped/DefinitelyTyped#64464](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/64464)).\nThis codemod tries to match the existing import style but isn't perfect.\nIf the import style doesn't match your preferences, you should set up auto-fixable lint rules to match this e.g. [`import/order`](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md).\n\n```diff\n+import { JSX } from 'react'\n-const element: JSX.Element = \u003cdiv /\u003e;\n+const element: JSX.Element = \u003cdiv /\u003e;\n```\n\n```diff\n import * as React from 'react';\n-const element: JSX.Element = \u003cdiv /\u003e;\n+const element: React.JSX.Element = \u003cdiv /\u003e;\n```\n\n### `useRef-required-initial` (React 19)\n\n`useRef` now always requires an initial value.\nImplicit `undefined` is forbidden.\n\n```diff\n import * as React from \"react\";\n-React.useRef()\n+React.useRef(undefined)\n```\n\n#### `useRef-required-initial` false-negative pattern A\n\nImporting `useRef` via aliased named import will result in the transform being skipped.\n\n```tsx\nimport { useRef as useReactRef } from \"react\";\n\n// not transformed\nuseReactRef\u003cnumber\u003e();\n```\n\n## Supported platforms\n\nThe following list contains officially supported runtimes.\nPlease file an issue for runtimes that are not included in this list.\n\n\u003c!-- #nodejs-suppport Should match CI test matrix --\u003e\n\n- Node.js `18.x || 20.x || 22.x`\n","funding_links":["https://github.com/sponsors/eps1lon"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feps1lon%2Ftypes-react-codemod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feps1lon%2Ftypes-react-codemod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feps1lon%2Ftypes-react-codemod/lists"}