feat(link): accept external URLs in Link to prop (#4901)#7678
Conversation
The runtime `useLinkProps` already detects absolute URLs in the `to`
prop (it parses `to` with `new URL()` and renders it as an anchor's
`href` when it looks external), but the type-level constraint from
`ToPathOption` rejected any string with a scheme — so users got a
TypeScript error for valid runtime usage:
<Link to="https://example.com" /> // TS error
<Link to="mailto:user@example.com" /> // TS error
<Link to="tel:+15551234567" /> // TS error
Widen `ToPathOption` to also accept the four protocols in the default
protocol allowlist (http:, https:, mailto:, tel:). Internal route paths
(`/dashboard`, `../profile`) continue to type-check unchanged — the
union only widens what is accepted.
Expose the new `ExternalUrl` template-literal type from router-core so
apps that want to type their own Link-like components can reuse it.
Fixes TanStack#4901
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Note: this PR was opened in draft state because the OAuth token used by my tooling does not have the GraphQL The change itself is straightforward: widen |
Summary
useLinkPropsalready detects absolute URLs in thetoprop at runtime — seepackages/react-router/src/link.tsx:113-154: it parsestowithnew URL()and renders it as an anchor'shrefwhen it looks external, still applyingisDangerousProtocolfiltering.But the type-level constraint from
ToPathOptionrejects any string with a scheme, so users get a TypeScript error for valid runtime usage:This PR widens
ToPathOptionto also accept the four protocols in the default protocol allowlist (http:,https:,mailto:,tel:). Internal route paths (/dashboard,../profile) continue to type-check unchanged — the union only widens what is accepted.It also exposes the new
ExternalUrltemplate-literal type from router-core so apps that want to type their own Link-like components can reuse it.Test plan
Added
packages/router-core/tests/external-url.test-d.tswith 7 type assertions covering:https://,http://,mailto:,tel:URL patterns matchingExternalUrlExternalUrlToPathOptionaccepting all four external URL protocolsToPathOptionstill accepting internal route paths (backward compat)Verified locally with
vitest --typecheck: 7/7 pass, no new type errors.Fixes #4901