mirror of https://github.com/vuejs/core.git
feat(types): provide ComponentInstance type (#5408)
This commit is contained in:
parent
44135dc95f
commit
bfb856565d
|
@ -0,0 +1,139 @@
|
|||
import {
|
||||
defineComponent,
|
||||
FunctionalComponent,
|
||||
ComponentPublicInstance,
|
||||
ComponentInstance,
|
||||
ref
|
||||
} from 'vue'
|
||||
import { expectType, describe } from './utils'
|
||||
|
||||
describe('defineComponent', () => {
|
||||
const CompSetup = defineComponent({
|
||||
props: {
|
||||
test: String
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
})
|
||||
const compSetup: ComponentInstance<typeof CompSetup> = {} as any
|
||||
|
||||
expectType<string | undefined>(compSetup.test)
|
||||
expectType<number>(compSetup.a)
|
||||
expectType<ComponentPublicInstance>(compSetup)
|
||||
})
|
||||
describe('functional component', () => {
|
||||
// Functional
|
||||
const CompFunctional: FunctionalComponent<{ test?: string }> = {} as any
|
||||
const compFunctional: ComponentInstance<typeof CompFunctional> = {} as any
|
||||
|
||||
expectType<string | undefined>(compFunctional.test)
|
||||
expectType<ComponentPublicInstance>(compFunctional)
|
||||
|
||||
const CompFunction: (props: { test?: string }) => any = {} as any
|
||||
const compFunction: ComponentInstance<typeof CompFunction> = {} as any
|
||||
|
||||
expectType<string | undefined>(compFunction.test)
|
||||
expectType<ComponentPublicInstance>(compFunction)
|
||||
})
|
||||
|
||||
describe('options component', () => {
|
||||
// Options
|
||||
const CompOptions = defineComponent({
|
||||
props: {
|
||||
test: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
a: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
b() {
|
||||
return 'test'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
func(a: string) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
const compOptions: ComponentInstance<typeof CompOptions> = {} as any
|
||||
expectType<string | undefined>(compOptions.test)
|
||||
expectType<number>(compOptions.a)
|
||||
expectType<(a: string) => boolean>(compOptions.func)
|
||||
expectType<ComponentPublicInstance>(compOptions)
|
||||
})
|
||||
|
||||
describe('object no defineComponent', () => {
|
||||
// object - no defineComponent
|
||||
|
||||
const CompObjectSetup = {
|
||||
props: {
|
||||
test: String
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
const compObjectSetup: ComponentInstance<typeof CompObjectSetup> = {} as any
|
||||
expectType<string | undefined>(compObjectSetup.test)
|
||||
expectType<number>(compObjectSetup.a)
|
||||
expectType<ComponentPublicInstance>(compObjectSetup)
|
||||
|
||||
const CompObjectData = {
|
||||
props: {
|
||||
test: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
const compObjectData: ComponentInstance<typeof CompObjectData> = {} as any
|
||||
expectType<string | undefined>(compObjectData.test)
|
||||
expectType<number>(compObjectData.a)
|
||||
expectType<ComponentPublicInstance>(compObjectData)
|
||||
|
||||
const CompObjectNoProps = {
|
||||
data() {
|
||||
return {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
const compObjectNoProps: ComponentInstance<typeof CompObjectNoProps> =
|
||||
{} as any
|
||||
expectType<string | undefined>(compObjectNoProps.test)
|
||||
expectType<number>(compObjectNoProps.a)
|
||||
expectType<ComponentPublicInstance>(compObjectNoProps)
|
||||
})
|
||||
|
||||
describe('Generic component', () => {
|
||||
const Comp = defineComponent(
|
||||
// TODO: babel plugin to auto infer runtime props options from type
|
||||
// similar to defineProps<{...}>()
|
||||
<T extends string | number>(props: { msg: T; list: T[] }) => {
|
||||
// use Composition API here like in <script setup>
|
||||
const count = ref(0)
|
||||
|
||||
return () => (
|
||||
// return a render function (both JSX and h() works)
|
||||
<div>
|
||||
{props.msg} {count.value}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// defaults to known types since types are resolved on instantiation
|
||||
const comp: ComponentInstance<typeof Comp> = {} as any
|
||||
expectType<string | number>(comp.msg)
|
||||
expectType<Array<string | number>>(comp.list)
|
||||
})
|
|
@ -83,6 +83,39 @@ import { LifecycleHooks } from './enums'
|
|||
|
||||
export type Data = Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Public utility type for extracting the instance type of a component.
|
||||
* Works with all valid component definition types. This is intended to replace
|
||||
* the usage of `InstanceType<typeof Comp>` which only works for
|
||||
* constructor-based component definition types.
|
||||
*
|
||||
* Exmaple:
|
||||
* ```ts
|
||||
* const MyComp = { ... }
|
||||
* declare const instance: ComponentInstance<typeof MyComp>
|
||||
* ```
|
||||
*/
|
||||
export type ComponentInstance<T> = T extends { new (): ComponentPublicInstance }
|
||||
? InstanceType<T>
|
||||
: T extends FunctionalComponent<infer Props, infer Emits>
|
||||
? ComponentPublicInstance<Props, {}, {}, {}, {}, Emits>
|
||||
: T extends Component<
|
||||
infer Props,
|
||||
infer RawBindings,
|
||||
infer D,
|
||||
infer C,
|
||||
infer M
|
||||
>
|
||||
? // NOTE we override Props/RawBindings/D to make sure is not `unknown`
|
||||
ComponentPublicInstance<
|
||||
unknown extends Props ? {} : Props,
|
||||
unknown extends RawBindings ? {} : RawBindings,
|
||||
unknown extends D ? {} : D,
|
||||
C,
|
||||
M
|
||||
>
|
||||
: never // not a vue Component
|
||||
|
||||
/**
|
||||
* For extending allowed non-declared props on components in TSX
|
||||
*/
|
||||
|
|
|
@ -230,7 +230,8 @@ export type {
|
|||
ComponentInternalInstance,
|
||||
SetupContext,
|
||||
ComponentCustomProps,
|
||||
AllowedComponentProps
|
||||
AllowedComponentProps,
|
||||
ComponentInstance
|
||||
} from './component'
|
||||
export type { DefineComponent, PublicProps } from './apiDefineComponent'
|
||||
export type {
|
||||
|
|
Loading…
Reference in New Issue