fix(nuxt,schema): prefer unknown rather than any for signatures (#21700)

This commit is contained in:
Daniel Roe 2023-06-22 14:14:21 +01:00 committed by GitHub
parent f380be910e
commit dd5dff37d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 41 deletions

View File

@ -32,7 +32,7 @@ interface PageMeta {
keepalive?: boolean | KeepAliveProps keepalive?: boolean | KeepAliveProps
layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey> layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey>
middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard> middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>
[key: string]: any [key: string]: unknown
} }
``` ```

View File

@ -1,4 +1,5 @@
import { useNuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt'
import type { NuxtPayload } from '#app'
/** /**
* Allows full control of the hydration cycle to set and receive data from the server. * Allows full control of the hydration cycle to set and receive data from the server.
@ -7,7 +8,7 @@ import { useNuxtApp } from '../nuxt'
* @param get a function that returns the value to set the initial data * @param get a function that returns the value to set the initial data
* @param set a function that will receive the data on the client-side * @param set a function that will receive the data on the client-side
*/ */
export const useHydration = <T> (key: string, get: () => T, set: (value: T) => void) => { export const useHydration = <K extends keyof NuxtPayload, T = NuxtPayload[K]> (key: K, get: () => T, set: (value: T) => void) => {
const nuxt = useNuxtApp() const nuxt = useNuxtApp()
if (process.server) { if (process.server) {
@ -18,7 +19,7 @@ export const useHydration = <T> (key: string, get: () => T, set: (value: T) => v
if (process.client) { if (process.client) {
nuxt.hooks.hook('app:created', () => { nuxt.hooks.hook('app:created', () => {
set(nuxt.payload[key]) set(nuxt.payload[key] as T)
}) })
} }
} }

View File

@ -5,9 +5,8 @@ import { useRuntimeConfig } from '#app'
export function useRequestURL () { export function useRequestURL () {
if (process.server) { if (process.server) {
const { baseURL } = useRuntimeConfig().app
const url = getRequestURL(useRequestEvent()) const url = getRequestURL(useRequestEvent())
url.pathname = joinURL(baseURL, url.pathname) url.pathname = joinURL(useRuntimeConfig().app.baseURL, url.pathname)
return url return url
} }
return new URL(window.location.href) return new URL(window.location.href)

View File

@ -58,7 +58,9 @@ export interface NuxtSSRContext extends SSRContext {
/** whether we are rendering an SSR error */ /** whether we are rendering an SSR error */
error?: boolean error?: boolean
nuxt: _NuxtApp nuxt: _NuxtApp
payload: _NuxtApp['payload'] payload: NuxtPayload
/** This is used solely to render runtime config with SPA renderer. */
config?: Pick<RuntimeConfig, 'public' | 'app'>
teleports?: Record<string, string> teleports?: Record<string, string>
renderMeta?: () => Promise<NuxtMeta> | NuxtMeta renderMeta?: () => Promise<NuxtMeta> | NuxtMeta
islandContext?: NuxtIslandContext islandContext?: NuxtIslandContext
@ -68,6 +70,25 @@ export interface NuxtSSRContext extends SSRContext {
_payloadReducers: Record<string, (data: any) => any> _payloadReducers: Record<string, (data: any) => any>
} }
export interface NuxtPayload {
path?: string
serverRendered?: boolean
prerenderedAt?: number
data: Record<string, any>
state: Record<string, any>
config?: Pick<RuntimeConfig, 'public' | 'app'>
error?: Error | {
url: string
statusCode: number
statusMessage: string
message: string
description: string
data?: any
} | null
_errors: Record<string, NuxtError | undefined>
[key: string]: unknown
}
interface _NuxtApp { interface _NuxtApp {
vueApp: App<Element> vueApp: App<Element>
globalName: string globalName: string
@ -120,23 +141,7 @@ interface _NuxtApp {
deferHydration: () => () => void | Promise<void> deferHydration: () => () => void | Promise<void>
ssrContext?: NuxtSSRContext ssrContext?: NuxtSSRContext
payload: { payload: NuxtPayload
path?: string
serverRendered?: boolean
prerenderedAt?: number
data: Record<string, any>
state: Record<string, any>
error?: Error | {
url: string
statusCode: number
statusMessage: string
message: string
description: string
data?: any
} | null
_errors: Record<string, NuxtError | undefined>
[key: string]: any
}
static: { static: {
data: Record<string, any> data: Record<string, any>
} }
@ -297,7 +302,7 @@ export function createNuxtApp (options: CreateOptions) {
} }
// Expose runtime config // Expose runtime config
const runtimeConfig = process.server ? options.ssrContext!.runtimeConfig : reactive(nuxtApp.payload.config) const runtimeConfig = process.server ? options.ssrContext!.runtimeConfig : reactive(nuxtApp.payload.config!)
nuxtApp.provide('config', runtimeConfig) nuxtApp.provide('config', runtimeConfig)
return nuxtApp return nuxtApp

View File

@ -101,6 +101,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
runtimeConfig: { runtimeConfig: {
...nuxt.options.runtimeConfig, ...nuxt.options.runtimeConfig,
nitro: { nitro: {
// @ts-expect-error TODO: https://github.com/unjs/nitro/pull/1336
envPrefix: 'NUXT_', envPrefix: 'NUXT_',
...nuxt.options.runtimeConfig.nitro ...nuxt.options.runtimeConfig.nitro
} }

View File

@ -14,7 +14,7 @@ import { defineRenderHandler, getRouteRules, useRuntimeConfig } from '#internal/
import { useNitroApp } from '#internal/nitro/app' import { useNitroApp } from '#internal/nitro/app'
// eslint-disable-next-line import/no-restricted-paths // eslint-disable-next-line import/no-restricted-paths
import type { NuxtApp, NuxtSSRContext } from '#app/nuxt' import type { NuxtPayload, NuxtSSRContext } from '#app/nuxt'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { appRootId, appRootTag } from '#internal/nuxt.config.mjs' import { appRootId, appRootTag } from '#internal/nuxt.config.mjs'
// @ts-expect-error virtual file // @ts-expect-error virtual file
@ -179,7 +179,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
// Whether we're rendering an error page // Whether we're rendering an error page
const ssrError = event.node.req.url?.startsWith('/__nuxt_error') const ssrError = event.node.req.url?.startsWith('/__nuxt_error')
? getQuery(event) as unknown as Exclude<NuxtApp['payload']['error'], Error> ? getQuery(event) as unknown as Exclude<NuxtPayload['error'], Error>
: null : null
if (ssrError && ssrError.statusCode) { if (ssrError && ssrError.statusCode) {
@ -230,7 +230,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
(process.env.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false), (process.env.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false),
error: !!ssrError, error: !!ssrError,
nuxt: undefined!, /* NuxtApp */ nuxt: undefined!, /* NuxtApp */
payload: (ssrError ? { error: ssrError } : {}) as NuxtSSRContext['payload'], payload: (ssrError ? { error: ssrError } : {}) as NuxtPayload,
_payloadReducers: {}, _payloadReducers: {},
islandContext islandContext
} }

View File

@ -5,7 +5,7 @@ import { useRoute } from 'vue-router'
import type { NuxtError } from '#app' import type { NuxtError } from '#app'
export interface PageMeta { export interface PageMeta {
[key: string]: any [key: string]: unknown
/** /**
* Validate whether a given route can validly be rendered with this page. * Validate whether a given route can validly be rendered with this page.
* *

View File

@ -10,7 +10,10 @@ declare global {
} }
declare module 'nitropack' { declare module 'nitropack' {
interface NitroRuntimeConfigApp extends RuntimeConfig['app'] {} interface NitroRuntimeConfigApp {
buildAssetsDir: string
cdnURL: string
}
interface NitroRuntimeConfig extends RuntimeConfig {} interface NitroRuntimeConfig extends RuntimeConfig {}
interface NitroRouteConfig { interface NitroRouteConfig {
ssr?: boolean ssr?: boolean

View File

@ -6,6 +6,7 @@ import type { Options as VueJsxPluginOptions } from '@vitejs/plugin-vue-jsx'
import type { AppHeadMetaObject } from './head' import type { AppHeadMetaObject } from './head'
import type { Nuxt } from './nuxt' import type { Nuxt } from './nuxt'
import type { SchemaDefinition } from 'untyped' import type { SchemaDefinition } from 'untyped'
import type { NitroRuntimeConfig, NitroRuntimeConfigApp } from 'nitropack'
export type { SchemaDefinition } from 'untyped' export type { SchemaDefinition } from 'untyped'
type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? { [P in keyof T]?: DeepPartial<T[P]> } : T type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? { [P in keyof T]?: DeepPartial<T[P]> } : T
@ -52,12 +53,14 @@ const message = Symbol('message')
export type RuntimeValue<T, B extends string> = T & { [message]?: B } export type RuntimeValue<T, B extends string> = T & { [message]?: B }
type Overrideable<T extends Record<string, any>, Path extends string = ''> = { type Overrideable<T extends Record<string, any>, Path extends string = ''> = {
[K in keyof T]?: K extends string [K in keyof T]?: K extends string
? T[K] extends Record<string, any> ? unknown extends T[K]
? RuntimeValue<Overrideable<T[K], `${Path}_${UpperSnakeCase<K>}`>, `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`> ? unknown
: RuntimeValue<T[K], `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`> : T[K] extends Record<string, unknown>
: K extends number ? RuntimeValue<Overrideable<T[K], `${Path}_${UpperSnakeCase<K>}`>, `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
? T[K] : RuntimeValue<T[K], `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
: never : K extends number
? T[K]
: never
} }
/** User configuration in `nuxt.config` file */ /** User configuration in `nuxt.config` file */
@ -128,11 +131,14 @@ export interface ViteConfig extends ViteUserConfig {
// -- Runtime Config -- // -- Runtime Config --
type RuntimeConfigNamespace = Record<string, any> type RuntimeConfigNamespace = Record<string, unknown>
export interface PublicRuntimeConfig extends RuntimeConfigNamespace { } export interface PublicRuntimeConfig extends RuntimeConfigNamespace { }
export interface RuntimeConfig extends RuntimeConfigNamespace { export interface RuntimeConfig extends RuntimeConfigNamespace {
app: NitroRuntimeConfigApp
/** Only available on the server. */
nitro?: NitroRuntimeConfig['nitro']
public: PublicRuntimeConfig public: PublicRuntimeConfig
} }

View File

@ -20,7 +20,7 @@ export interface ModuleMeta {
*/ */
compatibility?: NuxtCompatibility compatibility?: NuxtCompatibility
[key: string]: any [key: string]: unknown
} }
/** The options received. */ /** The options received. */

View File

@ -218,14 +218,14 @@ describe('runtimeConfig', () => {
expectTypeOf(runtimeConfig.public.needsFallback).toEqualTypeOf<string>() expectTypeOf(runtimeConfig.public.needsFallback).toEqualTypeOf<string>()
expectTypeOf(runtimeConfig.privateConfig).toEqualTypeOf<string>() expectTypeOf(runtimeConfig.privateConfig).toEqualTypeOf<string>()
expectTypeOf(runtimeConfig.public.ids).toEqualTypeOf<number[]>() expectTypeOf(runtimeConfig.public.ids).toEqualTypeOf<number[]>()
expectTypeOf(runtimeConfig.unknown).toEqualTypeOf<any>() expectTypeOf(runtimeConfig.unknown).toEqualTypeOf<unknown>()
const injectedConfig = useNuxtApp().$config const injectedConfig = useNuxtApp().$config
expectTypeOf(injectedConfig.public.testConfig).toEqualTypeOf<number>() expectTypeOf(injectedConfig.public.testConfig).toEqualTypeOf<number>()
expectTypeOf(injectedConfig.public.needsFallback).toEqualTypeOf<string>() expectTypeOf(injectedConfig.public.needsFallback).toEqualTypeOf<string>()
expectTypeOf(injectedConfig.privateConfig).toEqualTypeOf<string>() expectTypeOf(injectedConfig.privateConfig).toEqualTypeOf<string>()
expectTypeOf(injectedConfig.public.ids).toEqualTypeOf<number[]>() expectTypeOf(injectedConfig.public.ids).toEqualTypeOf<number[]>()
expectTypeOf(injectedConfig.unknown).toEqualTypeOf<any>() expectTypeOf(injectedConfig.unknown).toEqualTypeOf<unknown>()
}) })
it('provides hints on overriding these values', () => { it('provides hints on overriding these values', () => {
const val = defineNuxtConfig({ const val = defineNuxtConfig({
@ -241,8 +241,8 @@ describe('runtimeConfig', () => {
expectTypeOf(val.runtimeConfig!.privateConfig).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_PRIVATE_CONFIG'>>() expectTypeOf(val.runtimeConfig!.privateConfig).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_PRIVATE_CONFIG'>>()
expectTypeOf(val.runtimeConfig!.baseURL).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_URL'>>() expectTypeOf(val.runtimeConfig!.baseURL).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_URL'>>()
expectTypeOf(val.runtimeConfig!.baseAPIToken).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_API_TOKEN'>>() expectTypeOf(val.runtimeConfig!.baseAPIToken).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_API_TOKEN'>>()
expectTypeOf(val.runtimeConfig!.public!.ids).toEqualTypeOf<undefined | RuntimeValue<Array<number | undefined>, 'You can override this value at runtime with NUXT_PUBLIC_IDS'>>() expectTypeOf(val.runtimeConfig!.public!.ids).toEqualTypeOf<undefined | RuntimeValue<Array<number>, 'You can override this value at runtime with NUXT_PUBLIC_IDS'>>()
expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf<any>() expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf<unknown>()
}) })
}) })