新版的react-router-dom 與 tsconfig.json
React Router v6+ 與 tsconfig.json
TL;DR升級到 React Router v6 後 TS 編譯失敗?把 tsconfig.json 的 target 從 "es5" 改成 "ES2016"(或更新),因為 v6 內部用了 ES6+ 語法。
我的測試 demoreact-router-blp3hrsfv-bobo100.vercel.app
問題現場
升級 react-router-dom@6 後,build 出現:
Property 'matchAll' does not exist on type 'string'.
Property 'flatMap' does not exist on type 'Array'.
或者執行時:
TypeError: Cannot read properties of undefined (reading 'children')
原因
React Router v6 內部用了 ES2015+ 的 String/Array 方法(如 flatMap、matchAll、Array.from with iterator)。如果 tsconfig.json 的 target 還停在 "es5",TS lib 不會包含這些 API 的型別定義 → 編譯失敗。
修法
// tsconfig.json
{
"compilerOptions": {
"target": "ES2016", // ← 從 "es5" 改成這個(或更新)
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
為什麼至少 ES2016Array.prototype.includes 是 ES2016 加的,React Router v6 的 path 比對用得到。安全起見可以直接設 "ES2020" 或更新,反正現代瀏覽器都支援。
target vs lib 的差別
| 設定 | 影響 |
|---|---|
target | 決定 TS 編譯出來的 JS 用什麼語法(例:箭頭函式、async/await 是否要 polyfill) |
lib | 決定哪些內建型別可用(例:Array.flatMap / String.matchAll 的型別) |
target 設了之後 lib 預設會跟著,所以通常改 target 就夠了。如果只想要型別不想改編譯結果,單獨改 lib 即可。
各 React Router 版本最低 target
| 版本 | 最低 target | 重大改動 |
|---|---|---|
| v5 | ES5 | 舊 API |
| v6 | ES2016+ | <Routes> / useNavigate / useParams 等新 hooks |
| v6.4+ | ES2018+ | 加入 data API(loader / action) |
| v7 | ES2020+ | 與 Remix 合併 |
React Router v6 重點 API
import { BrowserRouter, Routes, Route, useNavigate, useParams } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/posts/:id" element={<Post />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
function Post() {
const { id } = useParams(); // 取代 v5 的 props.match.params
const navigate = useNavigate(); // 取代 v5 的 props.history
// ...
}