Skip to content

Commit

Permalink
fix(types): fix function prop type inference
Browse files Browse the repository at this point in the history
  • Loading branch information
kjleitz committed Mar 19, 2020
1 parent a59e05c commit ecc6e16
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
10 changes: 5 additions & 5 deletions types/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@ export type PropType<T> = Prop<T> | Prop<T>[];

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

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

export type RecordPropsDefinition<T> = {
[K in keyof T]: PropValidator<T[K]>
Expand Down
41 changes: 40 additions & 1 deletion types/test/vue-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Vue, { VNode } from "../index";
import { ComponentOptions } from "../options";
import { ComponentOptions, PropType } from "../options";

class Test extends Vue {
a: number = 0;
Expand Down Expand Up @@ -154,6 +154,45 @@ const FunctionalScopedSlotsComponent = Vue.extend({
}
});

declare function assertBoolean<A>(value: string extends A ? never : (A extends boolean ? A : never)): true;

declare const val1: boolean;
// declare const val2: boolean | (() => boolean);
// declare const val3: any;

assertBoolean(val1); //=> compiles (good)
// assertBoolean(val2); //=> does not compile (good)
// assertBoolean(val3); //=> does not compile (good)

const ComponentWithFunctionProps = Vue.extend({
props: {
functionProp: {
type: Function,
default: () => true,
},
functionPropWithBooleanReturnType: {
type: Function as PropType<() => boolean>,
default: () => true,
},
booleanProp: {
type: Boolean,
default: true,
},
booleanPropWithFunctionDefault: {
type: Boolean,
default: () => true,
},
},
methods: {
test(): void {
this.functionProp(); // callable (good)
assertBoolean(this.functionPropWithBooleanReturnType())
assertBoolean(this.booleanProp);
assertBoolean(this.booleanPropWithFunctionDefault);
},
},
});

const Parent = Vue.extend({
data() {
return { greeting: 'Hello' }
Expand Down

0 comments on commit ecc6e16

Please sign in to comment.