React17主项目引入React18模块遇TS类型错误,求非升级方案
React 17项目引入React 18模块的TypeScript编译问题解决方案
问题背景
主项目基于React 17开发,使用@types/react@17.0.44,引入基于React 18开发的@company/module模块后,tsc编译报错:
Module "react" has no exported member 'useId'
已设置skipLibCheck: true但问题仍存在。
问题解答
1. 无需升级主项目到React 18的修复方案
提供三种可行方案:
- 方案一:给目标模块添加类型声明补丁
在主项目src目录下创建types/@company/module/index.d.ts,手动声明模块导出类型,规避内部React类型冲突:
declare module '@company/module' { import type * as React from 'react'; // 替换为模块实际导出内容,示例如下: export const ModuleComponent: React.FC<{ /* 组件Props类型 */ }>; }
随后在tsconfig的include数组中添加该类型文件路径:
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx", "types/**/*.d.ts"]
- 方案二:补充React 18缺失的类型声明
在主项目根目录创建react-18-shim.d.ts,手动添加useId的类型声明:
import 'react'; declare module 'react' { function useId(): string; }
React 17运行时可兼容useIdAPI(会生成随机字符串),无运行时风险,同时解决编译报错。
- 方案三:调整tsconfig的检查范围
修改tsconfig的include和exclude,避免TypeScript检查@company/module的源码:
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"], "exclude": ["node_modules", "node_modules/@company/module/**/*"]
原配置中include使用**/*.ts会覆盖node_modules内文件,缩小范围后仅检查主项目源码即可跳过模块类型检查。
2. 让tsc为不同模块使用对应@types/react的方法
提供两种实现方式:
- 方式一:使用TypeScript项目引用(Project References)
将@company/module作为独立TypeScript项目,在其自身tsconfig.json中设置composite: true并指定React 18类型依赖;主项目tsconfig通过references字段引用该模块:
// 主项目tsconfig.json "references": [{"path": "../path/to/@company/module"}]
此方式下TypeScript会分别编译两个项目,各自使用对应@types/react版本,类型检查完全隔离。
- 方式二:通过paths映射指定模块的React类型
在主项目tsconfig的compilerOptions.paths中,为@company/module单独映射React类型路径:
"paths": { "~/*": ["src/*"], "@company/module/react": ["node_modules/@company/module/node_modules/@types/react"] }
注意:此方式需要模块内部的React导入路径改为@company/module/react,仅适用于模块源码可修改的场景。
主项目原tsconfig配置
{ "allowSyntheticDefaultImports": true, "compilerOptions": { "target": "es6", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, "forceConsistentCasingInFileNames": true, "noEmit": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "baseUrl": ".", "downLevelIteration": true, "paths": { "~/*": ["src/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] }
内容的提问来源于stack exchange,提问作者planktone
相关产品推荐
相关产品推荐

