From d9ad45ad6cf05c47d6a3438b57366d7d2146d13b Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 19 Oct 2020 22:25:55 +0100 Subject: [PATCH] types(defineComponent): fix optional Boolean prop types (#2401) fix #2338 --- packages/runtime-core/src/componentProps.ts | 19 +++++++++++++-- test-dts/defineComponent.test-d.tsx | 5 ++++ test-dts/h.test-d.ts | 26 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 938318d4..f1be9b76 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -65,13 +65,28 @@ type PropMethod = T extends (...args: any) => any // if i : never type RequiredKeys = { - [K in keyof T]: T[K] extends { required: true } | { default: any } ? K : never + [K in keyof T]: T[K] extends + | { required: true } + | { default: any } + // don't mark Boolean props as undefined + | BooleanConstructor + | { type: BooleanConstructor } + ? K + : never }[keyof T] type OptionalKeys = Exclude> type DefaultKeys = { - [K in keyof T]: T[K] extends { default: any } ? K : never + [K in keyof T]: T[K] extends + | { default: any } + // Boolean implicitly defaults to false + | BooleanConstructor + | { type: BooleanConstructor } + ? T[K] extends { type: BooleanConstructor; required: true } // not default if Boolean is marked as required + ? never + : K + : never }[keyof T] type InferPropType = T extends null diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index f201d660..c77feba0 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -19,6 +19,7 @@ describe('with object props', () => { a?: number | undefined b: string e?: Function + h: boolean bb: string bbb: string cc?: string[] | undefined @@ -46,6 +47,7 @@ describe('with object props', () => { required: true }, e: Function, + h: Boolean, // default value should infer type and make it non-void bb: { default: 'hello' @@ -108,6 +110,7 @@ describe('with object props', () => { expectType(props.a) expectType(props.b) expectType(props.e) + expectType(props.h) expectType(props.bb) expectType(props.bbb) expectType(props.cc) @@ -142,6 +145,7 @@ describe('with object props', () => { expectType(props.a) expectType(props.b) expectType(props.e) + expectType(props.h) expectType(props.bb) expectType(props.cc) expectType(props.dd) @@ -161,6 +165,7 @@ describe('with object props', () => { expectType(this.a) expectType(this.b) expectType(this.e) + expectType(this.h) expectType(this.bb) expectType(this.cc) expectType(this.dd) diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index 4376eaf9..877c6286 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -198,3 +198,29 @@ describe('component w/ props w/ default value', () => { h(MyComponent, {}) }) + +// #2338 +describe('Boolean prop implicit false', () => { + const MyComponent = defineComponent({ + props: { + visible: Boolean + } + }) + + h(MyComponent, {}) + + const RequiredComponent = defineComponent({ + props: { + visible: { + type: Boolean, + required: true + } + } + }) + + h(RequiredComponent, { + visible: true + }) + // @ts-expect-error + expectError(h(RequiredComponent, {})) +})