-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix(routerlink): allow event handlers under strictTemplates (fix #2484) #2548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for vue-router canceled.
|
WalkthroughRouterLink TypeScript typings were made generic to distinguish prop shapes when Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/router/src/RouterLink.ts (2)
1-31
: Prefer type-only import for AnchorHTMLAttributes to avoid any runtime import riskMove AnchorHTMLAttributes to a separate type-only import for consistency and to keep bundlers from attempting to load it at runtime.
-import { +import { defineComponent, h, PropType, inject, computed, reactive, unref, VNode, UnwrapRef, VNodeProps, AllowedComponentProps, ComponentCustomProps, getCurrentInstance, watchEffect, // this is a workaround for https://github.com/microsoft/rushstack/issues/1050 // this file is meant to be prepended to the generated dist/src/RouterLink.d.ts // @ts-ignore ComputedRef, // @ts-ignore DefineComponent, // @ts-ignore RendererElement, // @ts-ignore RendererNode, // @ts-ignore ComponentOptionsMixin, MaybeRef, - AnchorHTMLAttributes, } from 'vue' +import type { AnchorHTMLAttributes } from 'vue'
369-379
: Typing strategy achieves goal; verify behavior with dynamic booleancustom
bindingsThe conditional props cleanly allow anchor events/attrs when
custom !== true
and exclude them whencustom === true
, andhref
is properly omitted. One edge case:<RouterLink :custom="someBool" ...>
(or TSXcustom={someBool}
wheresomeBool: boolean
) may not be assignable to either branch of the union (true
vsfalse|undefined
), causing a TS error. If that’s acceptable, consider documenting it; otherwise, we may need a broader strategy (tradeoff: allowing dynamic booleans typically re-allows anchor attrs).You can extend the dts test with:
// dynamic boolean: today this likely errors (by design). Decide if we want to support it. const isCustom: boolean = Math.random() > 0.5 // @ts-expect-error: dynamic boolean not supported by narrowed props expectError(<RouterLink to="/" custom={isCustom} onFocus={() => {}} />) // explicit false should allow anchor attrs/handlers expectTypeOf<JSX.Element>(<RouterLink to="/" custom={false} onFocus={() => {}} target="_blank" />) // explicit true should forbid anchor attrs/handlers // @ts-expect-error expectError(<RouterLink to="/" custom={true} onFocus={() => {}} />)packages/router/test-dts/components.test-d.tsx (1)
30-40
: Great coverage; add a couple of assertions for explicitcustom={false}
and ARIA/data fallthroughTests capture the core behaviors. Consider adding:
- acceptance of
custom={false}
with events/attrs- an ARIA/data attribute to ensure broad fallthrough coverage
// allows when explicitly false expectTypeOf<JSX.Element>(<RouterLink to="/" custom={false} onFocus={() => {}} target="_blank" />) // allows ARIA/data attrs expectTypeOf<JSX.Element>(<RouterLink to="/" aria-label="Home" data-testid="rl" />)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/router/src/RouterLink.ts
(2 hunks)packages/router/test-dts/components.test-d.tsx
(1 hunks)
🔇 Additional comments (1)
packages/router/src/RouterLink.ts (1)
381-383
: Generic constructor change LGTMThis preserves inference in JSX while enabling the conditional props. No runtime impact; aligns with the stated objective.
9248c9f
to
b0ac394
Compare
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2548 +/- ##
=======================================
Coverage 89.61% 89.61%
=======================================
Files 46 46
Lines 4103 4103
Branches 1090 1090
=======================================
Hits 3677 3677
Misses 421 421
Partials 5 5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/router/test-dts/components.test-d.tsx (1)
30-40
: LGTM! Comprehensive type tests for RouterLink anchor behavior.The new tests correctly verify:
- Event handlers (
onFocus
,onClick
) and anchor attributes (target
,rel
) are allowed whencustom
is not sethref
is always disallowed (derived fromto
)- Event handlers are disallowed when
custom={true}
Optional enhancement: Consider adding a test for
custom={false}
explicitly to verify that anchor attributes are also allowed in that case (not just whencustom
is omitted):expectTypeOf<JSX.Element>( <RouterLink to="/" custom={false} onFocus={() => {}} /> )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/router/src/RouterLink.ts
(2 hunks)packages/router/test-dts/components.test-d.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/router/test-dts/components.test-d.tsx (2)
packages/router/src/RouterLink.ts (1)
RouterLink
(361-361)packages/router/src/index.ts (1)
RouterLink
(162-162)
packages/router/src/RouterLink.ts (1)
packages/router/src/index.ts (2)
RouterLinkProps
(165-165)_RouterLinkI
(164-164)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build
- GitHub Check: build
🔇 Additional comments (3)
packages/router/src/RouterLink.ts (3)
29-29
: LGTM! Correct import for anchor attributes and event handlers.Importing
AnchorHTMLAttributes
from Vue provides the complete set of anchor element attributes and event handlers needed for the type enhancement.
363-380
: LGTM! Well-designed conditional type for custom prop.The type definitions correctly implement the generic approach:
_RouterLinkPropsTypedBase
: Base props combining Vue component props + RouterLinkPropsRouterLinkPropsTyped<Custom>
: Conditional type that:
- When
Custom extends true
: Excludes anchor attributes (custom render mode)- Otherwise: Includes
Omit<AnchorHTMLAttributes, 'href'>
for anchor attributes/handlers- Always omits
href
since it's derived from theto
propThe conditional type correctly handles all scenarios via distributivity:
Custom = undefined
→ allows anchor attributes ✓Custom = false
→ allows anchor attributes ✓Custom = true
→ disallows anchor attributes ✓Custom = boolean
→ union of both branches (correctly permissive) ✓
389-390
: LGTM! Generic constructor enables precise type inference.Making
_RouterLinkI
generic overCustom
with a default ofboolean | undefined
allows TypeScript to:
- Infer
Custom = undefined
when thecustom
prop is omitted → anchor attributes allowed- Infer
Custom = true
whencustom
is passed → anchor attributes disallowedThis solves the strictTemplates issue while maintaining type safety and backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Description
With
vueCompilerOptions.strictTemplates: true
, adding any event handler toRouterLink
(e.g.@focus
) triggers a TS error, even though the handler works at runtime (see #2484).Solution
RouterLink
generic overcustom
to preserve anchor event/attrs whencustom !== true
and exclude them whencustom === true
.Omit<AnchorHTMLAttributes, 'href'>
sohref
stays disallowed (we derive it fromto
).Tests
Add dts tests to ensure:
custom
href
is not allowedcustom
istrue
All tests pass:
pnpm -C packages/router build && pnpm -C packages/router build:dts
pnpm -C packages/router test:types
pnpm -C packages/router test
(coverage/unit/e2e)Locally verified with
vue-tsc --noEmit
andstrictTemplates: true
on an SFC.Links
Closes #2484
Also happy to adjust if maintainers prefer another approach.
Summary by CodeRabbit
custom
, standard anchor attributes (e.g., target, rel) and native events are allowed whilehref
is excluded; when usingcustom
, native anchor events are restricted. No runtime changes.