From ecc6e1601962df5fd239ecab9276fd6655a1a54c Mon Sep 17 00:00:00 2001 From: Keegan Leitz Date: Thu, 19 Mar 2020 18:31:27 -0400 Subject: [PATCH] fix(types): fix function prop type inference close #9357 --- types/options.d.ts | 10 +++++----- types/test/vue-test.ts | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/types/options.d.ts b/types/options.d.ts index f49ca085e4e..e64054e1010 100644 --- a/types/options.d.ts +++ b/types/options.d.ts @@ -150,12 +150,12 @@ export type PropType = Prop | Prop[]; export type PropValidator = PropOptions | PropType; -export interface PropOptions { - type?: PropType; +export type PropOptions = (>() => { + 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 = { [K in keyof T]: PropValidator diff --git a/types/test/vue-test.ts b/types/test/vue-test.ts index 626220d0aac..bb450a33bd8 100644 --- a/types/test/vue-test.ts +++ b/types/test/vue-test.ts @@ -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; @@ -154,6 +154,45 @@ const FunctionalScopedSlotsComponent = Vue.extend({ } }); +declare function assertBoolean(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' }