]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(types): preserve and expose original options on defineComponent return type ...
authorZclhlmgqzc <31752986+Zclhlmgqzc@users.noreply.github.com>
Fri, 6 May 2022 09:44:05 +0000 (17:44 +0800)
committerGitHub <noreply@github.com>
Fri, 6 May 2022 09:44:05 +0000 (05:44 -0400)
fix #3796

packages/runtime-core/src/apiAsyncComponent.ts
packages/runtime-core/src/apiDefineComponent.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentPublicInstance.ts
test-dts/defineComponent.test-d.tsx

index 8825eefa5c62cdf9c6faf3dfa6c5f88c00aa64c3..dc92b90d7224416f792af9df7adc95c906e6832b 100644 (file)
@@ -111,7 +111,7 @@ export function defineAsyncComponent<
     )
   }
 
-  return defineComponent({
+  return defineComponent<{}>({
     name: 'AsyncComponentWrapper',
 
     __asyncLoader: load,
index 83446346fabe1f4ae2554eaf12b852dd7b1bc6bf..f0f69af34f65e73302cd767c2468d333704cf9d5 100644 (file)
@@ -6,7 +6,8 @@ import {
   ComponentOptionsWithObjectProps,
   ComponentOptionsMixin,
   RenderFunction,
-  ComponentOptionsBase
+  ComponentOptionsBase,
+  ComponentProvideOptions
 } from './componentOptions'
 import {
   SetupContext,
@@ -40,6 +41,8 @@ export type DefineComponent<
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = {},
   EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
+  RawOptions extends {} = {},
   PP = PublicProps,
   Props = Readonly<
     PropsOrPropOptions extends ComponentPropsOptions
@@ -48,22 +51,23 @@ export type DefineComponent<
   > &
     ({} extends E ? {} : EmitsToProps<E>),
   Defaults = ExtractDefaultPropTypes<PropsOrPropOptions>
-> = ComponentPublicInstanceConstructor<
-  CreateComponentPublicInstance<
-    Props,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    PP & Props,
-    Defaults,
-    true
+> = RawOptions &
+  ComponentPublicInstanceConstructor<
+    CreateComponentPublicInstance<
+      Props,
+      RawBindings,
+      D,
+      C,
+      M,
+      Mixin,
+      Extends,
+      E,
+      PP & Props,
+      Defaults,
+      true
+    > &
+      Props
   > &
-    Props
-> &
   ComponentOptionsBase<
     Props,
     RawBindings,
@@ -74,7 +78,8 @@ export type DefineComponent<
     Extends,
     E,
     EE,
-    Defaults
+    Defaults,
+    Provide
   > &
   PP
 
@@ -104,20 +109,36 @@ export function defineComponent<
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = EmitsOptions,
-  EE extends string = string
+  EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
+  Options extends {} = {}
 >(
-  options: ComponentOptionsWithoutProps<
-    Props,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    EE
-  >
-): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
+  options: Options &
+    ComponentOptionsWithoutProps<
+      Props,
+      RawBindings,
+      D,
+      C,
+      M,
+      Mixin,
+      Extends,
+      E,
+      EE,
+      Provide
+    >
+): DefineComponent<
+  Props,
+  RawBindings,
+  D,
+  C,
+  M,
+  Mixin,
+  Extends,
+  E,
+  EE,
+  Provide,
+  Options
+>
 
 // overload 3: object format with array props declaration
 // props inferred as { [key in PropNames]?: any }
@@ -131,19 +152,23 @@ export function defineComponent<
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = Record<string, any>,
-  EE extends string = string
+  EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
+  Options extends {} = {}
 >(
-  options: ComponentOptionsWithArrayProps<
-    PropNames,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    EE
-  >
+  options: Options &
+    ComponentOptionsWithArrayProps<
+      PropNames,
+      RawBindings,
+      D,
+      C,
+      M,
+      Mixin,
+      Extends,
+      E,
+      EE,
+      Provide
+    >
 ): DefineComponent<
   Readonly<{ [key in PropNames]?: any }>,
   RawBindings,
@@ -153,7 +178,9 @@ export function defineComponent<
   Mixin,
   Extends,
   E,
-  EE
+  EE,
+  Provide,
+  Options
 >
 
 // overload 4: object format with object props declaration
@@ -169,20 +196,36 @@ export function defineComponent<
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = Record<string, any>,
-  EE extends string = string
+  EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
+  Options extends {} = {}
 >(
-  options: ComponentOptionsWithObjectProps<
-    PropsOptions,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    EE
-  >
-): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>
+  options: Options &
+    ComponentOptionsWithObjectProps<
+      PropsOptions,
+      RawBindings,
+      D,
+      C,
+      M,
+      Mixin,
+      Extends,
+      E,
+      EE,
+      Provide
+    >
+): DefineComponent<
+  PropsOptions,
+  RawBindings,
+  D,
+  C,
+  M,
+  Mixin,
+  Extends,
+  E,
+  EE,
+  Provide,
+  Options
+>
 
 // implementation, close to no-op
 export function defineComponent(options: unknown) {
index e8fa676a25cdcd2d34fe78cecce19cc9b64109c8..b4fd4790543fc0bbb2428818306430a599a86472 100644 (file)
@@ -117,8 +117,9 @@ export interface ComponentOptionsBase<
   Extends extends ComponentOptionsMixin,
   E extends EmitsOptions,
   EE extends string = string,
-  Defaults = {}
-> extends LegacyOptions<Props, D, C, M, Mixin, Extends>,
+  Defaults = {},
+  Provide extends ComponentProvideOptions = ComponentProvideOptions
+> extends LegacyOptions<Props, D, C, M, Mixin, Extends, Provide>,
     ComponentInternalOptions,
     ComponentCustomOptions {
   setup?: (
@@ -224,6 +225,7 @@ export type ComponentOptionsWithoutProps<
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = EmitsOptions,
   EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
   PE = Props & EmitsToProps<E>
 > = ComponentOptionsBase<
   PE,
@@ -235,7 +237,8 @@ export type ComponentOptionsWithoutProps<
   Extends,
   E,
   EE,
-  {}
+  {},
+  Provide
 > & {
   props?: undefined
 } & ThisType<
@@ -252,6 +255,7 @@ export type ComponentOptionsWithArrayProps<
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = EmitsOptions,
   EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
   Props = Readonly<{ [key in PropNames]?: any }> & EmitsToProps<E>
 > = ComponentOptionsBase<
   Props,
@@ -263,7 +267,8 @@ export type ComponentOptionsWithArrayProps<
   Extends,
   E,
   EE,
-  {}
+  {},
+  Provide
 > & {
   props: PropNames[]
 } & ThisType<
@@ -289,6 +294,7 @@ export type ComponentOptionsWithObjectProps<
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
   E extends EmitsOptions = EmitsOptions,
   EE extends string = string,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions,
   Props = Readonly<ExtractPropTypes<PropsOptions>> & EmitsToProps<E>,
   Defaults = ExtractDefaultPropTypes<PropsOptions>
 > = ComponentOptionsBase<
@@ -301,7 +307,8 @@ export type ComponentOptionsWithObjectProps<
   Extends,
   E,
   EE,
-  Defaults
+  Defaults,
+  Provide
 > & {
   props: PropsOptions & ThisType<void>
 } & ThisType<
@@ -384,6 +391,10 @@ type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
 
 type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
 
+export type ComponentProvideOptions = ObjectProvideOptions | Function
+
+type ObjectProvideOptions = Record<string | symbol, unknown>
+
 type ComponentInjectOptions = string[] | ObjectInjectOptions
 
 type ObjectInjectOptions = Record<
@@ -397,7 +408,8 @@ interface LegacyOptions<
   C extends ComputedOptions,
   M extends MethodOptions,
   Mixin extends ComponentOptionsMixin,
-  Extends extends ComponentOptionsMixin
+  Extends extends ComponentOptionsMixin,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions
 > {
   compatConfig?: CompatConfig
 
@@ -431,7 +443,7 @@ interface LegacyOptions<
   computed?: C
   methods?: M
   watch?: ComponentWatchOptions
-  provide?: Data | Function
+  provide?: Provide
   inject?: ComponentInjectOptions
 
   // assets
index 03ee0e0e9a8fd211bb6dbc6d3dc5768b2769469a..faae5312d30641a393d2476a0e8b92b34ffb237b 100644 (file)
@@ -34,7 +34,8 @@ import {
   OptionTypesKeys,
   resolveMergedOptions,
   shouldCacheAccess,
-  MergedComponentOptionsOverride
+  MergedComponentOptionsOverride,
+  ComponentProvideOptions
 } from './componentOptions'
 import { EmitsOptions, EmitFn } from './componentEmits'
 import { Slots } from './componentSlots'
@@ -150,7 +151,8 @@ export type CreateComponentPublicInstance<
   PublicM extends MethodOptions = UnwrapMixinsType<PublicMixin, 'M'> &
     EnsureNonVoid<M>,
   PublicDefaults = UnwrapMixinsType<PublicMixin, 'Defaults'> &
-    EnsureNonVoid<Defaults>
+    EnsureNonVoid<Defaults>,
+  Provide extends ComponentProvideOptions = ComponentProvideOptions
 > = ComponentPublicInstance<
   PublicP,
   PublicB,
@@ -161,7 +163,19 @@ export type CreateComponentPublicInstance<
   PublicProps,
   PublicDefaults,
   MakeDefaultsOptional,
-  ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, Defaults>
+  ComponentOptionsBase<
+    P,
+    B,
+    D,
+    C,
+    M,
+    Mixin,
+    Extends,
+    E,
+    string,
+    Defaults,
+    Provide
+  >
 >
 
 // public properties exposed on the proxy, which is used as the render context
index 031b4a13eb85f05c41c3fa16a07a1cfaf6ca9aac..3c4e9cb39363ed403e557e95eefb0353c8f2647d 100644 (file)
@@ -49,96 +49,98 @@ describe('with object props', () => {
 
   type GT = string & { __brand: unknown }
 
-  const MyComponent = defineComponent({
-    props: {
-      a: Number,
-      // required should make property non-void
-      b: {
-        type: String,
-        required: true
-      },
-      e: Function,
-      h: Boolean,
-      j: Function as PropType<undefined | (() => string | undefined)>,
-      // default value should infer type and make it non-void
-      bb: {
-        default: 'hello'
-      },
-      bbb: {
-        // Note: default function value requires arrow syntax + explicit
-        // annotation
-        default: (props: any) => (props.bb as string) || 'foo'
-      },
-      bbbb: {
-        type: String,
-        default: undefined
-      },
-      bbbbb: {
-        type: String,
-        default: () => undefined
-      },
-      // explicit type casting
-      cc: Array as PropType<string[]>,
-      // required + type casting
-      dd: {
-        type: Object as PropType<{ n: 1 }>,
-        required: true
-      },
-      // return type
-      ee: Function as PropType<() => string>,
-      // arguments + object return
-      ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
-      // explicit type casting with constructor
-      ccc: Array as () => string[],
-      // required + constructor type casting
-      ddd: {
-        type: Array as () => string[],
-        required: true
-      },
-      // required + object return
-      eee: {
-        type: Function as PropType<() => { a: string }>,
-        required: true
-      },
-      // required + arguments + object return
-      fff: {
-        type: Function as PropType<(a: number, b: string) => { a: boolean }>,
-        required: true
-      },
-      hhh: {
-        type: Boolean,
-        required: true
-      },
-      // default + type casting
-      ggg: {
-        type: String as PropType<'foo' | 'bar'>,
-        default: 'foo'
-      },
-      // default + function
-      ffff: {
-        type: Function as PropType<(a: number, b: string) => { a: boolean }>,
-        default: (a: number, b: string) => ({ a: a > +b })
-      },
-      // union + function with different return types
-      iii: Function as PropType<(() => string) | (() => number)>,
-      // union + function with different args & same return type
-      jjj: {
-        type: Function as PropType<
-          ((arg1: string) => string) | ((arg1: string, arg2: string) => string)
-        >,
-        required: true
-      },
-      kkk: null,
-      validated: {
-        type: String,
-        // validator requires explicit annotation
-        validator: (val: unknown) => val !== ''
-      },
-      date: Date,
-      l: [Date],
-      ll: [Date, Number],
-      lll: [String, Number]
+  const props = {
+    a: Number,
+    // required should make property non-void
+    b: {
+      type: String,
+      required: true as true
+    },
+    e: Function,
+    h: Boolean,
+    j: Function as PropType<undefined | (() => string | undefined)>,
+    // default value should infer type and make it non-void
+    bb: {
+      default: 'hello'
+    },
+    bbb: {
+      // Note: default function value requires arrow syntax + explicit
+      // annotation
+      default: (props: any) => (props.bb as string) || 'foo'
+    },
+    bbbb: {
+      type: String,
+      default: undefined
+    },
+    bbbbb: {
+      type: String,
+      default: () => undefined
+    },
+    // explicit type casting
+    cc: Array as PropType<string[]>,
+    // required + type casting
+    dd: {
+      type: Object as PropType<{ n: 1 }>,
+      required: true as true
+    },
+    // return type
+    ee: Function as PropType<() => string>,
+    // arguments + object return
+    ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
+    // explicit type casting with constructor
+    ccc: Array as () => string[],
+    // required + constructor type casting
+    ddd: {
+      type: Array as () => string[],
+      required: true as true
+    },
+    // required + object return
+    eee: {
+      type: Function as PropType<() => { a: string }>,
+      required: true as true
+    },
+    // required + arguments + object return
+    fff: {
+      type: Function as PropType<(a: number, b: string) => { a: boolean }>,
+      required: true as true
+    },
+    hhh: {
+      type: Boolean,
+      required: true as true
+    },
+    // default + type casting
+    ggg: {
+      type: String as PropType<'foo' | 'bar'>,
+      default: 'foo'
     },
+    // default + function
+    ffff: {
+      type: Function as PropType<(a: number, b: string) => { a: boolean }>,
+      default: (a: number, b: string) => ({ a: a > +b })
+    },
+    // union + function with different return types
+    iii: Function as PropType<(() => string) | (() => number)>,
+    // union + function with different args & same return type
+    jjj: {
+      type: Function as PropType<
+        ((arg1: string) => string) | ((arg1: string, arg2: string) => string)
+      >,
+      required: true as true
+    },
+    kkk: null,
+    validated: {
+      type: String,
+      // validator requires explicit annotation
+      validator: (val: unknown) => val !== ''
+    },
+    date: Date,
+    l: [Date],
+    ll: [Date, Number],
+    lll: [String, Number]
+  }
+
+  const MyComponent = defineComponent({
+    props,
     setup(props) {
       // type assertion. See https://github.com/SamVerschueren/tsd
       expectType<ExpectedProps['a']>(props.a)
@@ -188,6 +190,9 @@ describe('with object props', () => {
         })
       }
     },
+    provide() {
+      return {}
+    },
     render() {
       const props = this.$props
       expectType<ExpectedProps['a']>(props.a)
@@ -258,6 +263,18 @@ describe('with object props', () => {
 
   expectType<Component>(MyComponent)
 
+  expectType<typeof props>(MyComponent.props)
+  // @ts-expect-error it should be an object and not any
+  expectError<[]>(MyComponent.props)
+
+  expectType<() => {}>(MyComponent.provide)
+  // @ts-expect-error
+  expectError<[]>(MyComponent.provide)
+
+  expectType<() => null>(MyComponent.render)
+
+  expectType<Function | undefined>(defineComponent({}).render)
+
   // Test TSX
   expectType<JSX.Element>(
     <MyComponent