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

View File

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

View File

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

View File

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

View File

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