From d9ba0d22494a2c3364dc130752351f46c5d5b0b7 Mon Sep 17 00:00:00 2001 From: Maik Kowol Date: Sat, 1 Feb 2025 14:45:12 +0100 Subject: [PATCH] fix(nuxt): ensure `` `fallback` prop is typed (#30832) --- .../nuxt/src/app/components/nuxt-layout.ts | 30 ++++++++++--------- test/fixtures/basic-types/types.ts | 9 ++++-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/nuxt/src/app/components/nuxt-layout.ts b/packages/nuxt/src/app/components/nuxt-layout.ts index 887f5fa9d4..74c8127ae2 100644 --- a/packages/nuxt/src/app/components/nuxt-layout.ts +++ b/packages/nuxt/src/app/components/nuxt-layout.ts @@ -1,4 +1,4 @@ -import type { DefineComponent, MaybeRef, VNode } from 'vue' +import type { DefineComponent, ExtractPublicPropTypes, MaybeRef, PropType, VNode } from 'vue' import { Suspense, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue' import type { RouteLocationNormalizedLoaded } from 'vue-router' @@ -30,19 +30,23 @@ const LayoutLoader = defineComponent({ }, }) +// props are moved outside of defineComponent to later explicitly assert the prop types +// this avoids type loss/simplification resulting in things like MaybeRef, keeping type hints for layout names +const nuxtLayoutProps = { + name: { + type: [String, Boolean, Object] as PropType : PageMeta['layout']>, + default: null, + }, + fallback: { + type: [String, Object] as PropType : PageMeta['layout']>, + default: null, + }, +} + export default defineComponent({ name: 'NuxtLayout', inheritAttrs: false, - props: { - name: { - type: [String, Boolean, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef : PageMeta['layout'], - default: null, - }, - fallback: { - type: [String, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef : PageMeta['layout'], - default: null, - }, - }, + props: nuxtLayoutProps, setup (props, context) { const nuxtApp = useNuxtApp() // Need to ensure (if we are not a child of ``) that we use synchronous route (not deferred) @@ -95,9 +99,7 @@ export default defineComponent({ }).default() } }, -}) as unknown as DefineComponent<{ - name?: (unknown extends PageMeta['layout'] ? MaybeRef : PageMeta['layout']) | undefined -}> +}) as DefineComponent> const LayoutProvider = defineComponent({ name: 'NuxtLayoutProvider', diff --git a/test/fixtures/basic-types/types.ts b/test/fixtures/basic-types/types.ts index d4cda0b4b5..4ed752a877 100644 --- a/test/fixtures/basic-types/types.ts +++ b/test/fixtures/basic-types/types.ts @@ -258,7 +258,7 @@ describe('typed router integration', () => { }) describe('layouts', () => { - it('recognizes named layouts', () => { + it('definePageMeta recognizes named layouts', () => { definePageMeta({ layout: 'custom' }) definePageMeta({ layout: 'pascal-case' }) definePageMeta({ layout: 'override' }) @@ -266,11 +266,14 @@ describe('layouts', () => { definePageMeta({ layout: 'invalid-layout' }) }) - it('allows typing layouts', () => { + it('NuxtLayout recognizes named layouts', () => { h(NuxtLayout, { name: 'custom' }) - // @ts-expect-error Invalid layout h(NuxtLayout, { name: 'invalid-layout' }) + + h(NuxtLayout, { fallback: 'custom' }) + // @ts-expect-error Invalid layout + h(NuxtLayout, { fallback: 'invalid-layout' }) }) })