{"slug": "catch-invented-react-imports-with-a-small-typescript-check", "title": "Catch Invented React Imports with a Small TypeScript Check", "summary": "A developer published a small TypeScript fixture that catches React imports pulled from the wrong package, such as importing createPortal from react instead of react-dom. Running tsc against the fixture with React and React DOM 19.2.8 and TypeScript 5.9.3 produced no diagnostics for correct imports and TS2724 for the deliberately wrong one, giving a failing control that confirms the check compiles the intended file. The technique is scoped to import boundaries only and does not render portals or verify DOM behavior.", "body_md": "*AI disclosure: OpenAI Codex drafted this tutorial. The examples below were checked by executing TypeScript against the listed installed packages. I maintain Ninna UI; this version uses standard React APIs. The example is a controlled reproduction, not a personal debugging story or a measurement of any agent's error rate.*\n\n*Cover created with AI-assisted vector code. It maps createPortal to react-dom and useState and Fragment to react.*\n\nA generated React feature can contain a familiar API name and still import it from the wrong package. A short TypeScript fixture turns that plausible import into something you can check before accepting the feature.\n\nThe useful technique is to check a few dependency boundaries and prove that the check fails for a known wrong import. A passing command alone is weaker evidence if the fixture was never included in the compilation.\n\nReact's documentation imports `createPortal` from `react-dom`. This intentionally incorrect fixture imports it from `react`:\n\n``` js\nimport { createPortal } from \"react\";\nvoid createPortal;\n```\n\nWith the installed versions used here, TypeScript reports TS2724: the `react` module has no exported member named `createPortal`. The fix is to use the right public entry point, rather than suppressing the diagnostic or inventing a local module declaration.\n\nIn an existing React/TypeScript project, create `react-import-audit.ts`:\n\n``` js\nimport { Fragment, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nvoid [Fragment, useState, createPortal];\n```\n\nThe file imports and references values but renders nothing. It does not call a Hook outside a component. The goal is just to resolve the exact exports used by a proposed feature.\n\nIf starting with a new project, install the required packages and keep the lockfile:\n\n```\npnpm add react@latest react-dom@latest\npnpm add -D typescript @types/react @types/react-dom\n```\n\nCreate `tsconfig.react-audit.json` beside the fixture:\n\n```\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n    \"types\": [\"react\", \"react-dom\"],\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"noEmit\": true\n  },\n  \"include\": [\"react-import-audit.ts\"]\n}\n```\n\nThis configuration checks one fixture without pulling in every application route. `bundler` resolution suits this bundled React example; use your framework's supported configuration for the actual app.\n\n```\npnpm exec tsc -p tsconfig.react-audit.json\n```\n\nFirst confirm that the correct fixture compiles. Then deliberately move `createPortal` into the import from `react` and remove its `react-dom` import. Confirm TS2724. Restore the correct imports and confirm success again. That failing control helps verify that the command is compiling the intended file.\n\n`noEmit` prevents JavaScript output. `skipLibCheck` skips checking declaration-file internals; it does not skip checking the imports in your source fixture. If the error is a missing dependency instead, inspect installation and the working directory before changing compiler options.\n\nAn agent instruction can be small and executable:\n\n```\nBefore changing a React import:\n1. Check the installed package's public exports and current docs.\n2. Keep a small fixture for the APIs the feature needs.\n3. Prove the fixture catches one known wrong package export.\n4. Run the app's normal typecheck and production build.\nDo not silence an export error with any, @ts-ignore,\nor a fabricated module declaration.\n```\n\nThe recorded check uses React and React DOM 19.2.8 with TypeScript 5.9.3. The correct fixture produced no diagnostics; the deliberately wrong import produced TS2724. Rerun it after dependency upgrades instead of assuming an old example describes the installed packages.\n\nThis checks an import boundary. It does not render a portal, verify the target DOM node, check event propagation, measure a bundle, or establish accessibility. A real feature still needs its normal typecheck, build, runtime tests and interaction checks. Passing declarations also cannot prove that runtime code perfectly matches its published types.\n\nStart with the APIs the feature actually uses. Keep the fixture small, prove it can fail, and keep broader application checks in the acceptance criteria.", "url": "https://wpnews.pro/news/catch-invented-react-imports-with-a-small-typescript-check", "canonical_source": "https://dev.to/chnkc41/catch-invented-react-imports-with-a-small-typescript-check-4cc4", "published_at": "2026-10-30 20:07:48+00:00", "updated_at": "2026-10-30 20:20:44.975776+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["React", "TypeScript", "Ninna UI", "OpenAI Codex"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/catch-invented-react-imports-with-a-small-typescript-check", "markdown": "https://wpnews.pro/news/catch-invented-react-imports-with-a-small-typescript-check.md", "text": "https://wpnews.pro/news/catch-invented-react-imports-with-a-small-typescript-check.txt", "jsonld": "https://wpnews.pro/news/catch-invented-react-imports-with-a-small-typescript-check.jsonld"}}