Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

refactor(nuxt): enable strict type checking #6368

Merged
merged 21 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/nuxt/src/app/compat/capi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ export * from 'vue'

export const install = () => {}

export function set (target, key, val) {
export function set (target: any, key: string | number | symbol, val: any) {
if (Array.isArray(target)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
target.length = Math.max(target.length, key as number)
target.splice(key as number, 1, val)
return val
}
target[key] = val
return val
}

export function del (target, key) {
export function del (target: any, key: string | number | symbol) {
if (Array.isArray(target)) {
target.splice(key, 1)
target.splice(key as number, 1)
return
}
delete target[key]
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/app/components/nuxt-error-boundary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineComponent({
}
},
setup (_props, { slots, emit }) {
const error = ref(null)
const error = ref<Error | null>(null)
const nuxtApp = useNuxtApp()

onErrorCaptured((err) => {
Expand Down
26 changes: 16 additions & 10 deletions packages/nuxt/src/app/components/nuxt-link.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent } from 'vue'
import { RouteLocationRaw, Router } from 'vue-router'
import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent, ComputedRef } from 'vue'
import { RouteLocationRaw } from 'vue-router'
import { hasProtocol } from 'ufo'

import { navigateTo, useRouter } from '#app'

const firstNonUndefined = <T>(...args: T[]): T => args.find(arg => arg !== undefined)
const firstNonUndefined = <T>(...args: (T | undefined)[]) => args.find(arg => arg !== undefined)

const DEFAULT_EXTERNAL_REL_ATTRIBUTE = 'noopener noreferrer'

Expand Down Expand Up @@ -39,7 +39,7 @@ export type NuxtLinkProps = {
export function defineNuxtLink (options: NuxtLinkOptions) {
const componentName = options.componentName || 'NuxtLink'

const checkPropConflicts = (props: NuxtLinkProps, main: string, sub: string): void => {
const checkPropConflicts = (props: NuxtLinkProps, main: keyof NuxtLinkProps, sub: keyof NuxtLinkProps): void => {
if (process.dev && props[main] !== undefined && props[sub] !== undefined) {
console.warn(`[${componentName}] \`${main}\` and \`${sub}\` cannot be used together. \`${sub}\` will be ignored.`)
}
Expand Down Expand Up @@ -116,18 +116,18 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
}
},
setup (props, { slots }) {
const router = useRouter() as Router | undefined
const router = useRouter()

// Resolving `to` value from `to` and `href` props
const to = computed<string | RouteLocationRaw>(() => {
const to: ComputedRef<string | RouteLocationRaw> = computed(() => {
checkPropConflicts(props, 'to', 'href')

return props.to || props.href || '' // Defaults to empty string (won't render any `href` attribute)
})

// Resolving link type
const isExternal = computed<boolean>(() => {
// External prop is explictly set
// External prop is explicitly set
if (props.external) {
return true
}
Expand Down Expand Up @@ -176,15 +176,21 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
// converts `""` to `null` to prevent the attribute from being added as empty (`rel=""`)
: firstNonUndefined<string | null>(props.rel, options.externalRelAttribute, href ? DEFAULT_EXTERNAL_REL_ATTRIBUTE : '') || null

const navigate = () => navigateTo(href, { replace: props.replace })
const navigate = () => {
if (href) {
navigateTo(href, { replace: props.replace })
antfu marked this conversation as resolved.
Show resolved Hide resolved
}
}

// https://router.vuejs.org/api/#custom
if (props.custom) {
if (!slots.default) { return null }
if (!slots.default) {
return null
}
return slots.default({
href,
navigate,
route: router.resolve(href),
route: href ? router.resolve(href) : undefined,
antfu marked this conversation as resolved.
Show resolved Hide resolved
rel,
target,
isActive: false,
Expand Down
6 changes: 3 additions & 3 deletions packages/nuxt/src/app/components/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { h } from 'vue'
import { defineComponent, h } from 'vue'
import type { Component } from 'vue'

const Fragment = {
const Fragment = defineComponent({
setup (_props, { slots }) {
return () => slots.default?.()
}
}
})

/**
* Internal utility
Expand Down
20 changes: 10 additions & 10 deletions packages/nuxt/src/app/composables/asyncData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref } from 'vue'
import type { Ref, WatchSource } from 'vue'
import { wrapInRef } from './utils'
import { NuxtApp, useNuxtApp } from '#app'

export type _Transform<Input = any, Output = any> = (input: Input) => Output
Expand All @@ -25,7 +24,7 @@ export interface AsyncDataOptions<
> {
server?: boolean
lazy?: boolean
default?: () => DataT | Ref<DataT>
default?: () => DataT | Ref<DataT> | null
transform?: Transform
pick?: PickKeys
watch?: MultiWatchSources
Expand All @@ -37,10 +36,10 @@ export interface RefreshOptions {
}

export interface _AsyncData<DataT, ErrorT> {
data: Ref<DataT>
data: Ref<DataT | null>
pending: Ref<boolean>
refresh: (opts?: RefreshOptions) => Promise<void>
error: Ref<ErrorT>
error: Ref<ErrorT | null>
}

export type AsyncData<Data, Error> = _AsyncData<Data, Error> & Promise<_AsyncData<Data, Error>>
Expand Down Expand Up @@ -70,7 +69,7 @@ export function useAsyncData<
DataE = Error,
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
> (...args): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) }

Expand Down Expand Up @@ -102,7 +101,8 @@ export function useAsyncData<
// Setup hook callbacks once per instance
const instance = getCurrentInstance()
if (instance && !instance._nuxtOnBeforeMountCbs) {
const cbs = instance._nuxtOnBeforeMountCbs = []
instance._nuxtOnBeforeMountCbs = []
const cbs = instance._nuxtOnBeforeMountCbs
if (instance && process.client) {
onBeforeMount(() => {
cbs.forEach((cb) => { cb() })
Expand All @@ -115,7 +115,7 @@ export function useAsyncData<
const useInitialCache = () => options.initialCache && nuxt.payload.data[key] !== undefined

const asyncData = {
data: wrapInRef(nuxt.payload.data[key] ?? options.default()),
data: ref(nuxt.payload.data[key] ?? options.default?.() ?? null),
pending: ref(!useInitialCache()),
error: ref(nuxt.payload._errors[key] ?? null)
} as AsyncData<DataT, DataE>
Expand Down Expand Up @@ -145,7 +145,7 @@ export function useAsyncData<
})
.catch((error: any) => {
asyncData.error.value = error
asyncData.data.value = unref(options.default())
asyncData.data.value = unref(options.default?.() ?? null)
})
.finally(() => {
asyncData.pending.value = false
Expand Down Expand Up @@ -224,7 +224,7 @@ export function useLazyAsyncData<
DataE = Error,
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
> (...args): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise<DataT>, AsyncDataOptions<DataT, Transform, PickKeys>]
Expand All @@ -243,7 +243,7 @@ export function refreshNuxtData (keys?: string | string[]): Promise<void> {
function pick (obj: Record<string, any>, keys: string[]) {
const newObj = {}
for (const key of keys) {
newObj[key] = obj[key]
(newObj as any)[key] = obj[key]
}
return newObj
}
8 changes: 3 additions & 5 deletions packages/nuxt/src/app/composables/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const NuxtComponentIndicator = '__nuxt_component'
async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<string, any>>, fn: (nuxtApp: NuxtApp) => Promise<Record<string, any>>) {
const nuxt = useNuxtApp()
const route = useRoute()
const vm = getCurrentInstance()
const { fetchKey } = vm.proxy.$options
const vm = getCurrentInstance()!
const { fetchKey } = vm.proxy!.$options
const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath
const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt))
if (data.value && typeof data.value === 'object') {
Expand Down Expand Up @@ -38,8 +38,7 @@ export const defineNuxtComponent: typeof defineComponent =
setup (props, ctx) {
const res = setup?.(props, ctx) || {}

let promises: unknown[] | undefined = []
promises = promises || []
const promises: Promise<any>[] = []
if (options.asyncData) {
promises.push(runLegacyAsyncData(res, options.asyncData))
}
Expand All @@ -49,7 +48,6 @@ export const defineNuxtComponent: typeof defineComponent =
.then(() => res)
.finally(() => {
promises.length = 0
promises = null
})
}
} as DefineComponent
Expand Down
11 changes: 5 additions & 6 deletions packages/nuxt/src/app/composables/cookie.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Ref, watch } from 'vue'
import { ref, Ref, watch } from 'vue'
import { parse, serialize, CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
import { appendHeader } from 'h3'
import type { CompatibilityEvent } from 'h3'
import destr from 'destr'
import { isEqual } from 'ohash'
import { useRequestEvent } from './ssr'
import { wrapInRef } from './utils'
import { useNuxtApp } from '#app'

type _CookieOptions = Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'>
Expand All @@ -24,11 +23,11 @@ const CookieDefaults: CookieOptions<any> = {
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
}

export function useCookie <T=string> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
export function useCookie <T = string> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
const opts = { ...CookieDefaults, ..._opts }
const cookies = readRawCookies(opts)
const cookies = readRawCookies(opts) || {}

const cookie = wrapInRef<T>(cookies[name] ?? opts.default?.())
const cookie = ref<T | undefined>(cookies[name] as any ?? opts.default?.())

if (process.client) {
watch(cookie, () => { writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) })
Expand All @@ -46,7 +45,7 @@ export function useCookie <T=string> (name: string, _opts?: CookieOptions<T>): C
return cookie as CookieRef<T>
}

function readRawCookies (opts: CookieOptions = {}): Record<string, string> {
function readRawCookies (opts: CookieOptions = {}): Record<string, string> | undefined {
if (process.server) {
return parse(useRequestEvent()?.req.headers.cookie || '', opts)
} else if (process.client) {
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/app/composables/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function useFetch<
arg1?: string | UseFetchOptions<_ResT, Transform, PickKeys>,
arg2?: string
) {
const [opts, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
const _key = opts.key || autoKey
if (!_key || typeof _key !== 'string') {
throw new TypeError('[nuxt] [useFetch] key must be a string: ' + _key)
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/app/composables/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {}
const nuxtApp = useNuxtApp()
if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) {
const redirectLocation = joinURL(useRuntimeConfig().app.baseURL, router.resolve(to).fullPath || '/')
return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext.event, redirectLocation, options.redirectCode || 302))
return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext!.event, redirectLocation, options.redirectCode || 302))
}
}
// Client-side redirection using vue-router
Expand Down
4 changes: 2 additions & 2 deletions packages/nuxt/src/app/composables/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { NuxtApp } from '#app/nuxt'

export function useRequestHeaders<K extends string = string> (include: K[]): Record<K, string | undefined>
export function useRequestHeaders (): Readonly<Record<string, string | undefined>>
export function useRequestHeaders (include?) {
export function useRequestHeaders (include?: any[]) {
if (process.client) { return {} }
const headers: Record<string, string | string[]> = useNuxtApp().ssrContext?.event.req.headers ?? {}
const headers = useNuxtApp().ssrContext?.event.req.headers ?? {}
if (!include) { return headers }
return Object.fromEntries(include.filter(key => headers[key]).map(key => [key, headers[key]]))
}
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/app/composables/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useNuxtApp } from '#app'
*/
export function useState <T> (key?: string, init?: (() => T | Ref<T>)): Ref<T>
export function useState <T> (init?: (() => T | Ref<T>)): Ref<T>
export function useState <T> (...args): Ref<T> {
export function useState <T> (...args: any): Ref<T> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
const [_key, init] = args as [string, (() => T | Ref<T>)]
Expand Down
3 changes: 0 additions & 3 deletions packages/nuxt/src/app/composables/utils.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/nuxt/src/app/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if (process.server) {
await nuxt.hooks.callHook('app:created', vueApp)
} catch (err) {
await nuxt.callHook('app:error', err)
ssrContext.error = ssrContext.error || err
ssrContext!.error ||= err
antfu marked this conversation as resolved.
Show resolved Hide resolved
}

return vueApp
Expand Down Expand Up @@ -81,7 +81,7 @@ if (process.client) {
}
}

entry().catch((error) => {
entry().catch((error: unknown) => {
console.error('Error while mounting app:', error) // eslint-disable-line no-console
})
}
Expand Down
22 changes: 11 additions & 11 deletions packages/nuxt/src/app/nuxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ interface _NuxtApp {

[key: string]: any

_asyncDataPromises?: Record<string, Promise<any>>
_asyncDataPromises: Record<string, Promise<any> | undefined>

ssrContext?: SSRContext & {
url: string
Expand All @@ -67,8 +67,8 @@ interface _NuxtApp {
}
payload: {
serverRendered?: boolean
data?: Record<string, any>
state?: Record<string, any>
data: Record<string, any>
state: Record<string, any>
rendered?: Function
[key: string]: any
}
Expand Down Expand Up @@ -127,23 +127,23 @@ export function createNuxtApp (options: CreateOptions) {
if (process.server) {
// Expose to server renderer to create window.__NUXT__
nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any
nuxtApp.ssrContext.payload = nuxtApp.payload
nuxtApp.ssrContext!.payload = nuxtApp.payload
}

// Expose client runtime-config to the payload
if (process.server) {
nuxtApp.payload.config = {
public: options.ssrContext.runtimeConfig.public,
app: options.ssrContext.runtimeConfig.app
public: options.ssrContext!.runtimeConfig.public,
app: options.ssrContext!.runtimeConfig.app
}
}

// Expose runtime config
const runtimeConfig = process.server
? options.ssrContext.runtimeConfig
? options.ssrContext!.runtimeConfig
: reactive(nuxtApp.payload.config)

// Backward compatibilty following #4254
// Backward compatibility following #4254
const compatibilityConfig = new Proxy(runtimeConfig, {
get (target, prop) {
if (prop === 'public') {
Expand Down Expand Up @@ -183,9 +183,9 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Plugin[]) {
}

export function normalizePlugins (_plugins: Plugin[]) {
const unwrappedPlugins = []
const legacyInjectPlugins = []
const invalidPlugins = []
const unwrappedPlugins: Plugin[] = []
const legacyInjectPlugins: Plugin[] = []
const invalidPlugins: Plugin[] = []

const plugins = _plugins.map((plugin) => {
if (typeof plugin !== 'function') {
Expand Down
Loading