From 43065b51032cf22c6cd4c9c274113a42ba561b9c Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 7 Aug 2022 15:46:37 +0100 Subject: [PATCH 1/4] types(defineProps): remove optional properties from type --- packages/runtime-core/src/apiSetupHelpers.ts | 9 ++++++++- packages/shared/src/typeUtils.ts | 9 +++++++++ test-dts/setupHelpers.test-d.ts | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts index a8b7fcdef31..2dc9371651d 100644 --- a/packages/runtime-core/src/apiSetupHelpers.ts +++ b/packages/runtime-core/src/apiSetupHelpers.ts @@ -58,7 +58,14 @@ export function defineProps< PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions >(props: PP): Readonly> // overload 3: typed-based declaration -export function defineProps(): Readonly +export function defineProps(): T extends object + ? { + // use needed to remove the optional property + [K in keyof Required]: K extends OptionalPropertyOf + ? T[K] | undefined + : T[K] + } + : Readonly // implementation export function defineProps() { if (__DEV__) { diff --git a/packages/shared/src/typeUtils.ts b/packages/shared/src/typeUtils.ts index 8730d7f38bf..29b9bae5e5d 100644 --- a/packages/shared/src/typeUtils.ts +++ b/packages/shared/src/typeUtils.ts @@ -10,3 +10,12 @@ export type LooseRequired = { [P in string & keyof T]: T[P] } // If the the type T accepts type "any", output type Y, otherwise output type N. // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360 export type IfAny = 0 extends 1 & T ? Y : N + +// Extract optional properties from a type +// https://stackoverflow.com/a/53899815 +export type OptionalPropertyOf = Exclude< + { + [K in keyof T]: T extends Record ? never : K + }[keyof T], + undefined +> diff --git a/test-dts/setupHelpers.test-d.ts b/test-dts/setupHelpers.test-d.ts index 6b9c67b2897..9a0f8988a75 100644 --- a/test-dts/setupHelpers.test-d.ts +++ b/test-dts/setupHelpers.test-d.ts @@ -13,9 +13,15 @@ describe('defineProps w/ type declaration', () => { // type declaration const props = defineProps<{ foo: string + x?: string }>() // explicitly declared type should be refined expectType(props.foo) + + // force check the actual type doing expectType(props.x) does not + // error when is not undefined, this way it does + // #6420 + expectType({} as unknown as string | undefined) // @ts-expect-error props.bar }) From 92458eb56b36499c110c01aa83276184dfe900e5 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 7 Aug 2022 15:50:00 +0100 Subject: [PATCH 2/4] import `OptionalPropertyOf` --- packages/runtime-core/src/apiSetupHelpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts index 2dc9371651d..c1b8041387e 100644 --- a/packages/runtime-core/src/apiSetupHelpers.ts +++ b/packages/runtime-core/src/apiSetupHelpers.ts @@ -1,5 +1,5 @@ import { ComponentPropsOptions } from '@vue/runtime-core' -import { isArray, isPromise, isFunction } from '@vue/shared' +import { isArray, isPromise, isFunction, OptionalPropertyOf } from '@vue/shared' import { getCurrentInstance, setCurrentInstance, From 6fc170cf0e990dff226dea0b5b537f20e6737d17 Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 6 Oct 2023 14:45:52 +0100 Subject: [PATCH 3/4] make changes --- packages/dts-test/setupHelpers.test-d.ts | 22 +++++++++++++++++++- packages/runtime-core/src/apiSetupHelpers.ts | 5 +++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts index feb4085dea0..7b038278447 100644 --- a/packages/dts-test/setupHelpers.test-d.ts +++ b/packages/dts-test/setupHelpers.test-d.ts @@ -8,7 +8,8 @@ import { defineSlots, VNode, Ref, - defineModel + defineModel, + toRefs } from 'vue' import { describe, expectType } from './utils' import { defineComponent } from 'vue' @@ -20,6 +21,7 @@ describe('defineProps w/ type declaration', () => { foo: string bool?: boolean boolAndUndefined: boolean | undefined + file?: File | File[] }>() // explicitly declared type should be refined expectType(props.foo) @@ -328,3 +330,21 @@ describe('useSlots', () => { const slots = useSlots() expectType(slots) }) + +describe('toRefs w/ type declaration', () => { + // type declaration + const props = defineProps<{ + foo: string + bool?: boolean + boolAndUndefined: boolean | undefined + file?: File | File[] + }>() + + // #6420 + expectType<{ + foo: Ref + bool: Ref + boolAndUndefined: Ref + file: Ref + }>(toRefs(props)) +}) diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts index 93200667081..cff0c6511e2 100644 --- a/packages/runtime-core/src/apiSetupHelpers.ts +++ b/packages/runtime-core/src/apiSetupHelpers.ts @@ -4,7 +4,8 @@ import { isFunction, Prettify, UnionToIntersection, - extend + extend, + LooseRequired } from '@vue/shared' import { getCurrentInstance, @@ -82,7 +83,7 @@ export function defineProps< >(props: PP): Prettify>> // overload 3: typed-based declaration export function defineProps(): DefineProps< - TypeProps, + LooseRequired, BooleanKey > // implementation From 50a41d3f41e469641c8bddb8565a90ad365ef84c Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 9 Nov 2023 14:47:25 +0800 Subject: [PATCH 4/4] Update setupHelpers.test-d.ts --- packages/dts-test/setupHelpers.test-d.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts index 7b038278447..838e376da2d 100644 --- a/packages/dts-test/setupHelpers.test-d.ts +++ b/packages/dts-test/setupHelpers.test-d.ts @@ -331,20 +331,10 @@ describe('useSlots', () => { expectType(slots) }) +// #6420 describe('toRefs w/ type declaration', () => { - // type declaration const props = defineProps<{ - foo: string - bool?: boolean - boolAndUndefined: boolean | undefined file?: File | File[] }>() - - // #6420 - expectType<{ - foo: Ref - bool: Ref - boolAndUndefined: Ref - file: Ref - }>(toRefs(props)) + expectType>(toRefs(props).file) })