fix(types): support inferring injected properties in options api (#6804)

close #3031
close #5931
This commit is contained in:
Rudy 2022-11-08 14:09:53 +08:00 committed by GitHub
parent 50e2253057
commit e4de623ea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 222 additions and 33 deletions

View File

@ -6,7 +6,8 @@ import {
ComponentOptionsWithObjectProps, ComponentOptionsWithObjectProps,
ComponentOptionsMixin, ComponentOptionsMixin,
RenderFunction, RenderFunction,
ComponentOptionsBase ComponentOptionsBase,
ComponentInjectOptions
} from './componentOptions' } from './componentOptions'
import { import {
SetupContext, SetupContext,
@ -104,7 +105,9 @@ export function defineComponent<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {}, E extends EmitsOptions = {},
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string
>( >(
options: ComponentOptionsWithoutProps< options: ComponentOptionsWithoutProps<
Props, Props,
@ -115,7 +118,9 @@ export function defineComponent<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> >
): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> ): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
@ -131,7 +136,9 @@ export function defineComponent<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {}, E extends EmitsOptions = {},
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string,
>( >(
options: ComponentOptionsWithArrayProps< options: ComponentOptionsWithArrayProps<
PropNames, PropNames,
@ -142,7 +149,9 @@ export function defineComponent<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> >
): DefineComponent< ): DefineComponent<
Readonly<{ [key in PropNames]?: any }>, Readonly<{ [key in PropNames]?: any }>,
@ -169,7 +178,9 @@ export function defineComponent<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {}, E extends EmitsOptions = {},
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string,
>( >(
options: ComponentOptionsWithObjectProps< options: ComponentOptionsWithObjectProps<
PropsOptions, PropsOptions,
@ -180,7 +191,9 @@ export function defineComponent<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> >
): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE> ): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>

View File

@ -118,8 +118,10 @@ export interface ComponentOptionsBase<
Extends extends ComponentOptionsMixin, Extends extends ComponentOptionsMixin,
E extends EmitsOptions, E extends EmitsOptions,
EE extends string = string, EE extends string = string,
Defaults = {} Defaults = {},
> extends LegacyOptions<Props, D, C, M, Mixin, Extends>, I extends ComponentInjectOptions = {},
II extends string = string
> extends LegacyOptions<Props, D, C, M, Mixin, Extends, I, II>,
ComponentInternalOptions, ComponentInternalOptions,
ComponentCustomOptions { ComponentCustomOptions {
setup?: ( setup?: (
@ -225,7 +227,9 @@ export type ComponentOptionsWithoutProps<
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions, E extends EmitsOptions = EmitsOptions,
EE extends string = string, EE extends string = string,
PE = Props & EmitsToProps<E> I extends ComponentInjectOptions = {},
II extends string = string,
PE = Props & EmitsToProps<E>,
> = ComponentOptionsBase< > = ComponentOptionsBase<
PE, PE,
RawBindings, RawBindings,
@ -236,11 +240,13 @@ export type ComponentOptionsWithoutProps<
Extends, Extends,
E, E,
EE, EE,
{} {},
I,
II
> & { > & {
props?: undefined props?: undefined
} & ThisType< } & ThisType<
CreateComponentPublicInstance<PE, RawBindings, D, C, M, Mixin, Extends, E> CreateComponentPublicInstance<PE, RawBindings, D, C, M, Mixin, Extends, E, PE, {}, false, I>
> >
export type ComponentOptionsWithArrayProps< export type ComponentOptionsWithArrayProps<
@ -253,6 +259,8 @@ export type ComponentOptionsWithArrayProps<
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions, E extends EmitsOptions = EmitsOptions,
EE extends string = string, EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string,
Props = Readonly<{ [key in PropNames]?: any }> & EmitsToProps<E> Props = Readonly<{ [key in PropNames]?: any }> & EmitsToProps<E>
> = ComponentOptionsBase< > = ComponentOptionsBase<
Props, Props,
@ -264,7 +272,9 @@ export type ComponentOptionsWithArrayProps<
Extends, Extends,
E, E,
EE, EE,
{} {},
I,
II
> & { > & {
props: PropNames[] props: PropNames[]
} & ThisType< } & ThisType<
@ -276,7 +286,11 @@ export type ComponentOptionsWithArrayProps<
M, M,
Mixin, Mixin,
Extends, Extends,
E E,
Props,
{},
false,
I
> >
> >
@ -290,8 +304,10 @@ export type ComponentOptionsWithObjectProps<
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions, E extends EmitsOptions = EmitsOptions,
EE extends string = string, EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string,
Props = Readonly<ExtractPropTypes<PropsOptions>> & EmitsToProps<E>, Props = Readonly<ExtractPropTypes<PropsOptions>> & EmitsToProps<E>,
Defaults = ExtractDefaultPropTypes<PropsOptions> Defaults = ExtractDefaultPropTypes<PropsOptions>,
> = ComponentOptionsBase< > = ComponentOptionsBase<
Props, Props,
RawBindings, RawBindings,
@ -302,7 +318,9 @@ export type ComponentOptionsWithObjectProps<
Extends, Extends,
E, E,
EE, EE,
Defaults Defaults,
I,
II
> & { > & {
props: PropsOptions & ThisType<void> props: PropsOptions & ThisType<void>
} & ThisType< } & ThisType<
@ -317,7 +335,8 @@ export type ComponentOptionsWithObjectProps<
E, E,
Props, Props,
Defaults, Defaults,
false false,
I
> >
> >
@ -389,20 +408,32 @@ export type ComponentProvideOptions = ObjectProvideOptions | Function
type ObjectProvideOptions = Record<string | symbol, unknown> type ObjectProvideOptions = Record<string | symbol, unknown>
type ComponentInjectOptions = string[] | ObjectInjectOptions export type ComponentInjectOptions = string[] | ObjectInjectOptions
type ObjectInjectOptions = Record< type ObjectInjectOptions = Record<
string | symbol, string | symbol,
string | symbol | { from?: string | symbol; default?: unknown } string | symbol | { from?: string | symbol; default?: unknown }
> >
export type InjectToObject<T extends ComponentInjectOptions> = T extends string[]
? {
[K in T[number]]?: unknown
}
: T extends ObjectInjectOptions
? {
[K in keyof T]?: unknown
}
: never
interface LegacyOptions< interface LegacyOptions<
Props, Props,
D, D,
C extends ComputedOptions, C extends ComputedOptions,
M extends MethodOptions, M extends MethodOptions,
Mixin extends ComponentOptionsMixin, Mixin extends ComponentOptionsMixin,
Extends extends ComponentOptionsMixin Extends extends ComponentOptionsMixin,
I extends ComponentInjectOptions,
II extends string
> { > {
compatConfig?: CompatConfig compatConfig?: CompatConfig
@ -437,7 +468,7 @@ interface LegacyOptions<
methods?: M methods?: M
watch?: ComponentWatchOptions watch?: ComponentWatchOptions
provide?: ComponentProvideOptions provide?: ComponentProvideOptions
inject?: ComponentInjectOptions inject?: I | II[]
// assets // assets
filters?: Record<string, Function> filters?: Record<string, Function>

View File

@ -34,7 +34,9 @@ import {
OptionTypesKeys, OptionTypesKeys,
resolveMergedOptions, resolveMergedOptions,
shouldCacheAccess, shouldCacheAccess,
MergedComponentOptionsOverride MergedComponentOptionsOverride,
InjectToObject,
ComponentInjectOptions
} from './componentOptions' } from './componentOptions'
import { EmitsOptions, EmitFn } from './componentEmits' import { EmitsOptions, EmitFn } from './componentEmits'
import { Slots } from './componentSlots' import { Slots } from './componentSlots'
@ -141,6 +143,7 @@ export type CreateComponentPublicInstance<
PublicProps = P, PublicProps = P,
Defaults = {}, Defaults = {},
MakeDefaultsOptional extends boolean = false, MakeDefaultsOptional extends boolean = false,
I extends ComponentInjectOptions = {},
PublicMixin = IntersectionMixin<Mixin> & IntersectionMixin<Extends>, PublicMixin = IntersectionMixin<Mixin> & IntersectionMixin<Extends>,
PublicP = UnwrapMixinsType<PublicMixin, 'P'> & EnsureNonVoid<P>, PublicP = UnwrapMixinsType<PublicMixin, 'P'> & EnsureNonVoid<P>,
PublicB = UnwrapMixinsType<PublicMixin, 'B'> & EnsureNonVoid<B>, PublicB = UnwrapMixinsType<PublicMixin, 'B'> & EnsureNonVoid<B>,
@ -150,7 +153,7 @@ export type CreateComponentPublicInstance<
PublicM extends MethodOptions = UnwrapMixinsType<PublicMixin, 'M'> & PublicM extends MethodOptions = UnwrapMixinsType<PublicMixin, 'M'> &
EnsureNonVoid<M>, EnsureNonVoid<M>,
PublicDefaults = UnwrapMixinsType<PublicMixin, 'Defaults'> & PublicDefaults = UnwrapMixinsType<PublicMixin, 'Defaults'> &
EnsureNonVoid<Defaults> EnsureNonVoid<Defaults>,
> = ComponentPublicInstance< > = ComponentPublicInstance<
PublicP, PublicP,
PublicB, PublicB,
@ -161,7 +164,8 @@ export type CreateComponentPublicInstance<
PublicProps, PublicProps,
PublicDefaults, PublicDefaults,
MakeDefaultsOptional, MakeDefaultsOptional,
ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, Defaults> ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, Defaults>,
I
> >
// public properties exposed on the proxy, which is used as the render context // public properties exposed on the proxy, which is used as the render context
@ -176,7 +180,8 @@ export type ComponentPublicInstance<
PublicProps = P, PublicProps = P,
Defaults = {}, Defaults = {},
MakeDefaultsOptional extends boolean = false, MakeDefaultsOptional extends boolean = false,
Options = ComponentOptionsBase<any, any, any, any, any, any, any, any, any> Options = ComponentOptionsBase<any, any, any, any, any, any, any, any, any>,
I extends ComponentInjectOptions = {}
> = { > = {
$: ComponentInternalInstance $: ComponentInternalInstance
$data: D $data: D
@ -205,7 +210,8 @@ export type ComponentPublicInstance<
UnwrapNestedRefs<D> & UnwrapNestedRefs<D> &
ExtractComputedReturns<C> & ExtractComputedReturns<C> &
M & M &
ComponentCustomProperties ComponentCustomProperties &
InjectToObject<I>
export type PublicPropertiesMap = Record< export type PublicPropertiesMap = Record<
string, string,

View File

@ -222,7 +222,8 @@ export {
RenderFunction, RenderFunction,
MethodOptions, MethodOptions,
ComputedOptions, ComputedOptions,
RuntimeCompilerOptions RuntimeCompilerOptions,
ComponentInjectOptions
} from './componentOptions' } from './componentOptions'
export { EmitsOptions, ObjectEmitsOptions } from './componentEmits' export { EmitsOptions, ObjectEmitsOptions } from './componentEmits'
export { export {

View File

@ -19,7 +19,8 @@ import {
nextTick, nextTick,
warn, warn,
ConcreteComponent, ConcreteComponent,
ComponentOptions ComponentOptions,
ComponentInjectOptions
} from '@vue/runtime-core' } from '@vue/runtime-core'
import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared' import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared'
import { hydrate, render } from '.' import { hydrate, render } from '.'
@ -49,7 +50,9 @@ export function defineCustomElement<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions, E extends EmitsOptions = EmitsOptions,
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string
>( >(
options: ComponentOptionsWithoutProps< options: ComponentOptionsWithoutProps<
Props, Props,
@ -60,7 +63,9 @@ export function defineCustomElement<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> & { styles?: string[] } > & { styles?: string[] }
): VueElementConstructor<Props> ): VueElementConstructor<Props>
@ -74,7 +79,9 @@ export function defineCustomElement<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>, E extends EmitsOptions = Record<string, any>,
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string
>( >(
options: ComponentOptionsWithArrayProps< options: ComponentOptionsWithArrayProps<
PropNames, PropNames,
@ -85,7 +92,9 @@ export function defineCustomElement<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> & { styles?: string[] } > & { styles?: string[] }
): VueElementConstructor<{ [K in PropNames]: any }> ): VueElementConstructor<{ [K in PropNames]: any }>
@ -99,7 +108,9 @@ export function defineCustomElement<
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>, E extends EmitsOptions = Record<string, any>,
EE extends string = string EE extends string = string,
I extends ComponentInjectOptions = {},
II extends string = string
>( >(
options: ComponentOptionsWithObjectProps< options: ComponentOptionsWithObjectProps<
PropsOptions, PropsOptions,
@ -110,7 +121,9 @@ export function defineCustomElement<
Mixin, Mixin,
Extends, Extends,
E, E,
EE EE,
I,
II
> & { styles?: string[] } > & { styles?: string[] }
): VueElementConstructor<ExtractPropTypes<PropsOptions>> ): VueElementConstructor<ExtractPropTypes<PropsOptions>>

View File

@ -1033,6 +1033,68 @@ describe('emits', () => {
}) })
}) })
describe('inject', () => {
// with object inject
defineComponent({
props: {
a: String
},
inject: {
foo: 'foo',
bar: 'bar',
},
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// with array inject
defineComponent({
props: ['a', 'b'],
inject: ['foo', 'bar'],
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// with no props
defineComponent({
inject: {
foo: {
from: 'pfoo',
default: 'foo'
},
bar: {
from: 'pbar',
default: 'bar'
},
},
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// without inject
defineComponent({
props: ['a', 'b'],
created() {
// @ts-expect-error
expectError(this.foo = 1)
// @ts-expect-error
expectError(this.bar = 1)
}
})
})
describe('componentOptions setup should be `SetupContext`', () => { describe('componentOptions setup should be `SetupContext`', () => {
expectType<ComponentOptions['setup']>( expectType<ComponentOptions['setup']>(
{} as (props: Record<string, any>, ctx: SetupContext) => any {} as (props: Record<string, any>, ctx: SetupContext) => any

View File

@ -0,0 +1,63 @@
import { defineCustomElement, expectType, expectError } from './index'
describe('inject', () => {
// with object inject
defineCustomElement({
props: {
a: String
},
inject: {
foo: 'foo',
bar: 'bar',
},
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// with array inject
defineCustomElement({
props: ['a', 'b'],
inject: ['foo', 'bar'],
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// with no props
defineCustomElement({
inject: {
foo: {
from: 'pbar',
default: 'foo'
},
bar: {
from: 'pfoo',
default: 'bar'
},
},
created() {
expectType<unknown>(this.foo)
expectType<unknown>(this.bar)
// @ts-expect-error
expectError(this.foobar = 1)
}
})
// without inject
defineCustomElement({
props: ['a', 'b'],
created() {
// @ts-expect-error
expectError(this.foo = 1)
// @ts-expect-error
expectError(this.bar = 1)
}
})
})