diff --git a/packages/types/app/vue.d.ts b/packages/types/app/vue.d.ts index 116059648e..4aad87a128 100644 --- a/packages/types/app/vue.d.ts +++ b/packages/types/app/vue.d.ts @@ -5,14 +5,32 @@ import Vue from 'vue' import { MetaInfo } from 'vue-meta' import { Route } from 'vue-router' +import { RecordPropsDefinition, PropsDefinition, ComponentOptions } from 'vue/types/options' +import { CombinedVueInstance, ExtendedVue } from 'vue/types/vue' import { NuxtRuntimeConfig } from '../config/runtime' import { Context, Middleware, Transition, NuxtApp } from './index' +// https://github.com/vuejs/vue/blob/dev/types/options.d.ts#L63-L66 +type DefaultData = object | ((this: V) => object) +type DefaultProps = Record +type DefaultMethods = { [key: string]: (this: V, ...args: any[]) => any } +type DefaultComputed = { [key: string]: any } +type DefaultAsyncData = ((this: V, context: Context) => Promise | object | void) + declare module 'vue/types/options' { - // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars - interface ComponentOptions { + interface ComponentOptions< + V extends Vue, + /* eslint-disable no-unused-vars,@typescript-eslint/no-unused-vars */ + Data = DefaultData, + Methods = DefaultMethods, + Computed = DefaultComputed, + PropsDef = PropsDefinition, + Props = DefaultProps, + /* eslint-enable no-unused-vars,@typescript-eslint/no-unused-vars */ + AsyncData = DefaultAsyncData + > { // eslint-disable-next-line @typescript-eslint/ban-types - asyncData?(ctx: Context): Promise | object | void + asyncData?: AsyncData fetch?(ctx: Context): Promise | void fetchKey?: string | ((getKey: (id: string) => number) => string) fetchDelay?: number @@ -30,6 +48,59 @@ declare module 'vue/types/options' { } } +type DataDef = Data | ((this: Readonly & V) => Data) +type Awaited = T extends PromiseLike ? Awaited : T +type Merged = { + [key in keyof Data | keyof AsyncData]: key extends keyof Data ? key extends keyof AsyncData ? NonNullable | AsyncData[key] : Data[key] : key extends keyof AsyncData ? AsyncData[key] : never +} + +type ThisTypedComponentOptionsWithArrayPropsAndAsyncData< + V extends Vue, + Data, + Methods, + Computed, + PropNames extends string, + AsyncData +> = object & + ComponentOptions< + V, + DataDef, V>, + Methods, + Computed, + PropNames[], + Record, + DataDef + > & + ThisType< + CombinedVueInstance< + V, + Merged>, + Methods, + Computed, + Readonly> + > + > +export type ThisTypedComponentOptionsWithRecordPropsAndAsyncData< + V extends Vue, + Data, + Methods, + Computed, + Props, + AsyncData +> = object & + ComponentOptions< + V, + DataDef, + Methods, + Computed, + RecordPropsDefinition, + Props, + DataDef +> & + ThisType< + CombinedVueInstance>, Methods, Computed, Readonly> + > + declare module 'vue/types/vue' { interface Vue { $config: NuxtRuntimeConfig @@ -41,4 +112,26 @@ declare module 'vue/types/vue' { timestamp: number } } + interface VueConstructor { + extend( + options?: ThisTypedComponentOptionsWithArrayPropsAndAsyncData< + V, + Data, + Methods, + Computed, + PropNames, + AsyncData + > + ): ExtendedVue> + extend( + options?: ThisTypedComponentOptionsWithRecordPropsAndAsyncData< + V, + Data, + Methods, + Computed, + Props, + AsyncData + > + ): ExtendedVue + } }