]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(types): declared prop keys should always exist in `props` argument (#3726)
authorGU Yiling <justice360@gmail.com>
Wed, 12 May 2021 21:47:31 +0000 (05:47 +0800)
committerGitHub <noreply@github.com>
Wed, 12 May 2021 21:47:31 +0000 (17:47 -0400)
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/helpers/typeUtils.ts
test-dts/component.test-d.ts

index 0fd25bc7156b6b0400916dc7f69fe0d857c4f481..7c55033ce505ebc3557ee559a44e058df1fb0448 100644 (file)
@@ -65,7 +65,7 @@ import {
 import { warn } from './warning'
 import { VNodeChild } from './vnode'
 import { callWithAsyncErrorHandling } from './errorHandling'
-import { UnionToIntersection } from './helpers/typeUtils'
+import { LooseRequired, UnionToIntersection } from './helpers/typeUtils'
 import { deepMergeData } from './compat/data'
 import { DeprecationTypes } from './compat/compatConfig'
 import {
@@ -130,9 +130,13 @@ export interface ComponentOptionsBase<
     ComponentCustomOptions {
   setup?: (
     this: void,
-    props: Props &
-      UnionToIntersection<ExtractOptionProp<Mixin>> &
-      UnionToIntersection<ExtractOptionProp<Extends>>,
+    props: Readonly<
+      LooseRequired<
+        Props &
+          UnionToIntersection<ExtractOptionProp<Mixin>> &
+          UnionToIntersection<ExtractOptionProp<Extends>>
+      >
+    >,
     ctx: SetupContext<E>
   ) => Promise<RawBindings> | RawBindings | RenderFunction | void
   name?: string
index 64bf512938534a5e7fda767513d232843ba8e9e0..222e72714af748faaa25e8f09eaaae2217497ff0 100644 (file)
@@ -3,3 +3,6 @@ export type UnionToIntersection<U> = (U extends any
   : never) extends ((k: infer I) => void)
   ? I
   : never
+
+// make keys required but keep undefined values
+export type LooseRequired<T> = { [P in string & keyof T]: T[P] }
index 06368e377787b17e5241b4daade6402bb531fdb2..e679ffa6a4034f6e6bc45b631480bc008da5986b 100644 (file)
@@ -9,7 +9,8 @@ import {
   expectType,
   ShallowUnwrapRef,
   FunctionalComponent,
-  ComponentPublicInstance
+  ComponentPublicInstance,
+  toRefs
 } from './index'
 
 declare function extractComponentOptions<Props, RawBindings>(
@@ -42,6 +43,27 @@ describe('object props', () => {
     object?: object
   }
 
+  interface ExpectedRefs {
+    a: Ref<number | undefined>
+    b: Ref<string>
+    e: Ref<Function | undefined>
+    bb: Ref<string>
+    bbb: Ref<string>
+    cc: Ref<string[] | undefined>
+    dd: Ref<{ n: 1 }>
+    ee: Ref<(() => string) | undefined>
+    ff: Ref<((a: number, b: string) => { a: boolean }) | undefined>
+    ccc: Ref<string[] | undefined>
+    ddd: Ref<string[]>
+    eee: Ref<() => { a: string }>
+    fff: Ref<(a: number, b: string) => { a: boolean }>
+    hhh: Ref<boolean>
+    ggg: Ref<'foo' | 'bar'>
+    ffff: Ref<(a: number, b: string) => { a: boolean }>
+    validated: Ref<string | undefined>
+    object: Ref<object | undefined>
+  }
+
   describe('defineComponent', () => {
     const MyComponent = defineComponent({
       props: {
@@ -111,6 +133,26 @@ describe('object props', () => {
         object: Object as PropType<object>
       },
       setup(props) {
+        const refs = toRefs(props)
+        expectType<ExpectedRefs['a']>(refs.a)
+        expectType<ExpectedRefs['b']>(refs.b)
+        expectType<ExpectedRefs['e']>(refs.e)
+        expectType<ExpectedRefs['bb']>(refs.bb)
+        expectType<ExpectedRefs['bbb']>(refs.bbb)
+        expectType<ExpectedRefs['cc']>(refs.cc)
+        expectType<ExpectedRefs['dd']>(refs.dd)
+        expectType<ExpectedRefs['ee']>(refs.ee)
+        expectType<ExpectedRefs['ff']>(refs.ff)
+        expectType<ExpectedRefs['ccc']>(refs.ccc)
+        expectType<ExpectedRefs['ddd']>(refs.ddd)
+        expectType<ExpectedRefs['eee']>(refs.eee)
+        expectType<ExpectedRefs['fff']>(refs.fff)
+        expectType<ExpectedRefs['hhh']>(refs.hhh)
+        expectType<ExpectedRefs['ggg']>(refs.ggg)
+        expectType<ExpectedRefs['ffff']>(refs.ffff)
+        expectType<ExpectedRefs['validated']>(refs.validated)
+        expectType<ExpectedRefs['object']>(refs.object)
+
         return {
           setupA: 1,
           setupB: ref(1),