diff --git a/src/component/componentProps.ts b/src/component/componentProps.ts index 0198f053..0b6cfc21 100644 --- a/src/component/componentProps.ts +++ b/src/component/componentProps.ts @@ -30,6 +30,16 @@ type RequiredKeys = { type OptionalKeys = Exclude>; +type ExtractFunctionPropType< + T extends Function, + TArgs extends Array = any[], + TResult = any +> = T extends (...args: TArgs) => TResult ? T : never; + +type ExtractCorrectPropType = T extends Function + ? ExtractFunctionPropType + : Exclude; + // prettier-ignore type InferPropType = T extends null ? any // null & true would fail to infer @@ -38,7 +48,7 @@ type InferPropType = T extends null : T extends ObjectConstructor | { type: ObjectConstructor } ? { [key: string]: any } : T extends Prop - ? V + ? ExtractCorrectPropType : T; // prettier-ignore diff --git a/test/types/defineComponent.spec.ts b/test/types/defineComponent.spec.ts index d7b940fd..0deeca71 100644 --- a/test/types/defineComponent.spec.ts +++ b/test/types/defineComponent.spec.ts @@ -1,11 +1,16 @@ -import { createComponent, defineComponent, createElement as h, ref, SetupContext, PropType } from '../../src'; +import { + createComponent, + defineComponent, + createElement as h, + ref, + SetupContext, + PropType, +} from '../../src'; import Router from 'vue-router'; const Vue = require('vue/dist/vue.common.js'); -type Equal = (() => U extends Left ? 1 : 0) extends (() => U extends Right - ? 1 - : 0) +type Equal = (() => U extends Left ? 1 : 0) extends () => U extends Right ? 1 : 0 ? true : false; @@ -105,6 +110,28 @@ describe('defineComponent', () => { expect.assertions(3); }); + it('custom props type inferred from PropType', () => { + interface User { + name: string; + } + const App = defineComponent({ + props: { + user: Object as PropType, + func: Function as PropType<() => boolean>, + userFunc: Function as PropType<(u: User) => User>, + }, + setup(props) { + type PropsType = typeof props; + isSubType<{ user?: User }, PropsType>(true); + isSubType boolean; userFunc?: (u: User) => User }>( + true + ); + }, + }); + new Vue(App); + expect.assertions(2); + }); + it('no props', () => { const App = defineComponent({ setup(props, ctx) {