Skip to content

Commit ecc6e16

Browse files
committed
fix(types): fix function prop type inference
close vuejs#9357
1 parent a59e05c commit ecc6e16

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

types/options.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@ export type PropType<T> = Prop<T> | Prop<T>[];
150150

151151
export type PropValidator<T> = PropOptions<T> | PropType<T>;
152152

153-
export interface PropOptions<T=any> {
154-
type?: PropType<T>;
153+
export type PropOptions<T=any> = (<TypeAsAccessed extends T, TypeAsDefined extends PropType<T>>() => {
154+
type?: TypeAsDefined;
155155
required?: boolean;
156-
default?: T | null | undefined | (() => T | null | undefined);
157-
validator?(value: T): boolean;
158-
}
156+
default?: TypeAsDefined extends PropType<(...args: any[]) => any> ? TypeAsAccessed | null | undefined : TypeAsAccessed | null | undefined | (() => TypeAsAccessed | null | undefined);
157+
validator?(value: TypeAsAccessed): boolean;
158+
}) extends () => infer Opts ? Opts : never;
159159

160160
export type RecordPropsDefinition<T> = {
161161
[K in keyof T]: PropValidator<T[K]>

types/test/vue-test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Vue, { VNode } from "../index";
2-
import { ComponentOptions } from "../options";
2+
import { ComponentOptions, PropType } from "../options";
33

44
class Test extends Vue {
55
a: number = 0;
@@ -154,6 +154,45 @@ const FunctionalScopedSlotsComponent = Vue.extend({
154154
}
155155
});
156156

157+
declare function assertBoolean<A>(value: string extends A ? never : (A extends boolean ? A : never)): true;
158+
159+
declare const val1: boolean;
160+
// declare const val2: boolean | (() => boolean);
161+
// declare const val3: any;
162+
163+
assertBoolean(val1); //=> compiles (good)
164+
// assertBoolean(val2); //=> does not compile (good)
165+
// assertBoolean(val3); //=> does not compile (good)
166+
167+
const ComponentWithFunctionProps = Vue.extend({
168+
props: {
169+
functionProp: {
170+
type: Function,
171+
default: () => true,
172+
},
173+
functionPropWithBooleanReturnType: {
174+
type: Function as PropType<() => boolean>,
175+
default: () => true,
176+
},
177+
booleanProp: {
178+
type: Boolean,
179+
default: true,
180+
},
181+
booleanPropWithFunctionDefault: {
182+
type: Boolean,
183+
default: () => true,
184+
},
185+
},
186+
methods: {
187+
test(): void {
188+
this.functionProp(); // callable (good)
189+
assertBoolean(this.functionPropWithBooleanReturnType())
190+
assertBoolean(this.booleanProp);
191+
assertBoolean(this.booleanPropWithFunctionDefault);
192+
},
193+
},
194+
});
195+
157196
const Parent = Vue.extend({
158197
data() {
159198
return { greeting: 'Hello' }

0 commit comments

Comments
 (0)