From 18b6885dfce7ad317bfeedcbfb4ad24787921348 Mon Sep 17 00:00:00 2001 From: Bryan Ross Date: Tue, 29 Oct 2024 16:18:57 -0600 Subject: [PATCH 1/4] Fix types for UIMatch to reflect data may be undefined --- .changeset/thick-snails-compete.md | 8 ++++++++ packages/react-router/lib/router/utils.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .changeset/thick-snails-compete.md diff --git a/.changeset/thick-snails-compete.md b/.changeset/thick-snails-compete.md new file mode 100644 index 0000000000..6da85aacdb --- /dev/null +++ b/.changeset/thick-snails-compete.md @@ -0,0 +1,8 @@ +--- +"@react-router/remix-routes-option-adapter": patch +"@react-router/fs-routes": patch +"@react-router/dev": patch +"react-router": patch +--- + +Fix types for UIMatch to reflect that data may be undefined diff --git a/packages/react-router/lib/router/utils.ts b/packages/react-router/lib/router/utils.ts index 8a913a80db..e911fb1e30 100644 --- a/packages/react-router/lib/router/utils.ts +++ b/packages/react-router/lib/router/utils.ts @@ -532,7 +532,7 @@ export interface UIMatch { id: string; pathname: string; params: AgnosticRouteMatch["params"]; - data: Data; + data: Data | undefined; handle: Handle; } From 5f709d88fa8dff40d5bdb9af7baa58ffaa59930e Mon Sep 17 00:00:00 2001 From: Bryan Ross Date: Tue, 29 Oct 2024 16:27:05 -0600 Subject: [PATCH 2/4] add name to contributors.yml --- contributors.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/contributors.yml b/contributors.yml index 09cfbf1df5..ca27fee356 100644 --- a/contributors.yml +++ b/contributors.yml @@ -222,6 +222,7 @@ - robbtraister - RobHannay - robinvdvleuten +- rossipedia - rtmann - rubeonline - ryanflorence From 0d40752d07c277e2b72ae805d38bf3f8e01ad348 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 5 Aug 2025 11:15:07 -0400 Subject: [PATCH 3/4] Update changeset --- .changeset/thick-snails-compete.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.changeset/thick-snails-compete.md b/.changeset/thick-snails-compete.md index 6da85aacdb..1b939e0b0d 100644 --- a/.changeset/thick-snails-compete.md +++ b/.changeset/thick-snails-compete.md @@ -1,7 +1,4 @@ --- -"@react-router/remix-routes-option-adapter": patch -"@react-router/fs-routes": patch -"@react-router/dev": patch "react-router": patch --- From bc128915e35faf2be88e04f27f3dde0d90973a5d Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 5 Aug 2025 11:39:46 -0400 Subject: [PATCH 4/4] Add more details to changeset --- .changeset/thick-snails-compete.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.changeset/thick-snails-compete.md b/.changeset/thick-snails-compete.md index 1b939e0b0d..e16e5bc32e 100644 --- a/.changeset/thick-snails-compete.md +++ b/.changeset/thick-snails-compete.md @@ -2,4 +2,26 @@ "react-router": patch --- -Fix types for UIMatch to reflect that data may be undefined +Fix types for `UIMatch` to reflect that the `loaderData`/`data` properties may be `undefined` + +- When an `ErrorBoundary` is being rendered, not all active matches will have loader data available, since it may have been their `loader` that threw to trigger the boundary +- The `UIMatch.data` type was not correctly handing this and would always reflect the presence of data, leading to the unexpected runtime errors when an `ErrorBoundary` was rendered +- ⚠️ This may cause some type errors to show up in your code for unguarded `match.data` accesses - you should properly guard for `undefined` values in those scenarios. + +```tsx +// app/root.tsx +export function loader() { + someFunctionThatThrows(); // ❌ Throws an Error + return { title: "My Title" }; +} + +export function Layout({ children }: { children: React.ReactNode }) { + let matches = useMatches(); + let rootMatch = matches[0] as UIMatch>>; + // ^ rootMatch.data is incorrectly typed here, so TypeScript does not + // complain if you do the following which throws an error at runtime: + let { title } = rootMatch.data; // 💥 + + return ...; +} +```