feat(nuxt): add types for default NuxtLink slot (#31104)

This commit is contained in:
Maik Kowol 2025-02-27 10:55:36 +01:00 committed by Daniel Roe
parent 71de708a05
commit a4e6069a4b
No known key found for this signature in database
GPG Key ID: 3714AB03996F442B
2 changed files with 38 additions and 9 deletions

View File

@ -2,17 +2,21 @@ import type {
AllowedComponentProps,
AnchorHTMLAttributes,
ComputedRef,
DefineComponent,
InjectionKey, PropType,
DefineSetupFnComponent,
InjectionKey,
PropType,
SlotsType,
UnwrapRef,
VNode,
VNodeProps,
} from 'vue'
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue'
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, useLink } from 'vue-router'
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, UseLinkReturn, useLink } from 'vue-router'
import { hasProtocol, joinURL, parseQuery, withTrailingSlash, withoutTrailingSlash } from 'ufo'
import { preloadRouteComponents } from '../composables/preload'
import { onNuxtReady } from '../composables/ready'
import { navigateTo, resolveRouteObject, useRouter } from '../composables/router'
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
import { type NuxtApp, useNuxtApp, useRuntimeConfig } from '../nuxt'
import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback'
// @ts-expect-error virtual file
@ -28,7 +32,8 @@ const NuxtLinkDevKeySymbol: InjectionKey<boolean> = Symbol('nuxt-link-dev-key')
* `<NuxtLink>` is a drop-in replacement for both Vue Router's `<RouterLink>` component and HTML's `<a>` tag.
* @see https://nuxt.com/docs/api/components/nuxt-link
*/
export interface NuxtLinkProps extends Omit<RouterLinkProps, 'to'> {
export interface NuxtLinkProps<CustomProp extends boolean = false> extends Omit<RouterLinkProps, 'to'> {
custom?: CustomProp
/**
* Route Location the link should navigate to when clicked on.
*/
@ -102,6 +107,24 @@ export interface NuxtLinkOptions extends
prefetchOn?: Exclude<NuxtLinkProps['prefetchOn'], string>
}
type NuxtLinkDefaultSlotProps<CustomProp extends boolean = false> = CustomProp extends true
? {
href: string
navigate: () => Promise<void>
prefetch: (nuxtApp?: NuxtApp) => Promise<void>
route: (RouteLocation & { href: string }) | undefined
rel: string | null
target: '_blank' | '_parent' | '_self' | '_top' | (string & {}) | null
isExternal: boolean
isActive: false
isExactActive: false
}
: UnwrapRef<UseLinkReturn>
type NuxtLinkSlots<CustomProp extends boolean = false> = {
default?: (props: NuxtLinkDefaultSlotProps<CustomProp>) => VNode[]
}
/* @__NO_SIDE_EFFECTS__ */
export function defineNuxtLink (options: NuxtLinkOptions) {
const componentName = options.componentName || 'NuxtLink'
@ -466,14 +489,19 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
isExternal: isExternal.value || hasTarget.value,
isActive: false,
isExactActive: false,
})
} satisfies NuxtLinkDefaultSlotProps<true>)
}
// converts `""` to `null` to prevent the attribute from being added as empty (`href=""`)
return h('a', { ref: el, href: href.value || null, rel, target }, slots.default?.())
}
},
}) as unknown as DefineComponent<NuxtLinkProps>
// }) as unknown as DefineComponent<NuxtLinkProps, object, object, ComputedOptions, MethodOptions, object, object, EmitsOptions, string, object, NuxtLinkProps, object, SlotsType<NuxtLinkSlots>>
}) as unknown as new<CustomProp extends boolean = false>(props: NuxtLinkProps<CustomProp>) => InstanceType<DefineSetupFnComponent<
NuxtLinkProps<CustomProp>,
[],
SlotsType<NuxtLinkSlots<CustomProp>>
>>
}
export default defineNuxtLink(nuxtLinkDefaults)

View File

@ -55,8 +55,9 @@ const nuxtLink = (
): { type: string, props: Record<string, unknown>, slots: unknown } => {
const component = defineNuxtLink({ componentName: 'NuxtLink', ...nuxtLinkOptions })
const [type, _props, slots] = (component.setup as unknown as (props: NuxtLinkProps, context: { slots: Record<string, () => unknown> }) =>
() => [string, Record<string, unknown>, unknown])(props, { slots: { default: () => null } })()
const [type, _props, slots] = (
component as unknown as { setup: (props: NuxtLinkProps, context: { slots: Record<string, () => unknown> }) => () => [string, Record<string, unknown>, unknown] }
).setup(props, { slots: { default: () => null } })()
return { type, props: _props, slots }
}