Repository: vuejs/composition-api
Pull request #627 (2021-01-08 12:46:13)

fix: Date infer string in props

Zcating: see this issue: [Setting "Date" type as props will infer to string in the setup function](https://github.com/vuejs/vue-next/issues/2668), I copied from it.

Patch:
diff --git a/src/component/componentProps.ts b/src/component/componentProps.ts
index c27ff15..d01ee3e 100644
--- a/src/component/componentProps.ts
+++ b/src/component/componentProps.ts
@@ -51,13 +51,15 @@ type InferPropType<T> = T extends null
       ? Record<string, any>
       : T extends BooleanConstructor | { type: BooleanConstructor }
         ? boolean
-        : T extends FunctionConstructor
-          ? Function
-          : T extends Prop<infer V, infer D>
-            ? unknown extends V
-              ? D
-              : ExtractCorrectPropType<V>
-            : T
+          : T extends DateConstructor | { type: DateConstructor}
+            ? Date
+              : T extends FunctionConstructor
+                ? Function
+                : T extends Prop<infer V, infer D>
+                  ? unknown extends V
+                    ? D
+                    : ExtractCorrectPropType<V>
+                  : T
 
 export type ExtractPropTypes<O> = O extends object
   ? { [K in RequiredKeys<O>]: InferPropType<O[K]> } &
diff --git a/src/install.ts b/src/install.ts
index a21159b..09cfe42 100644
--- a/src/install.ts
+++ b/src/install.ts
@@ -1,6 +1,6 @@
 import type { VueConstructor } from 'vue'
 import { AnyObject } from './types/basic'
-import { hasSymbol, hasOwn, isPlainObject, assert, warn } from './utils'
+import { hasSymbol, hasOwn, isPlainObject, warn } from './utils'
 import { isRef } from './reactivity'
 import { setVueConstructor, isVueRegistered } from './runtimeContext'
 import { mixin } from './mixin'
@@ -42,9 +42,8 @@ function mergeData(from: AnyObject, to: AnyObject): Object {
 export function install(Vue: VueConstructor) {
   if (isVueRegistered(Vue)) {
     if (__DEV__) {
-      assert(
-        false,
-        'already installed. Vue.use(VueCompositionAPI) should be called only once.'
+      warn(
+        '[vue-composition-api] already installed. Vue.use(VueCompositionAPI) should be called only once.'
       )
     }
     return
@@ -53,10 +52,12 @@ export function install(Vue: VueConstructor) {
   if (__DEV__) {
     if (Vue.version) {
       if (Vue.version[0] !== '2' || Vue.version[1] !== '.') {
-        assert(false, `only works with Vue 2, v${Vue.version} found.`)
+        warn(
+          `[vue-composition-api] only works with Vue 2, v${Vue.version} found.`
+        )
       }
     } else {
-      warn('Vue version not found')
+      warn('[vue-composition-api] no Vue version found')
     }
   }
 
diff --git a/src/runtimeContext.ts b/src/runtimeContext.ts
index 81089ad..64e2a65 100644
--- a/src/runtimeContext.ts
+++ b/src/runtimeContext.ts
@@ -61,7 +61,7 @@ export function getRegisteredVueOrDefault(): VueConstructor {
 export function setVueConstructor(Vue: VueConstructor) {
   // @ts-ignore
   if (__DEV__ && vueConstructor && Vue.__proto__ !== vueConstructor.__proto__) {
-    warn('Another instance of vue installed')
+    warn('[vue-composition-api] another instance of Vue installed')
   }
   vueConstructor = Vue
   Object.defineProperty(Vue, PluginInstalledFlag, {
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 2c4f4fc..32d0961 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -45,7 +45,9 @@ export function hasOwn(obj: Object, key: string): boolean {
 }
 
 export function assert(condition: any, msg: string) {
-  if (!condition) throw new Error(`[vue-composition-api] ${msg}`)
+  if (!condition) {
+    throw new Error(`[vue-composition-api] ${msg}`)
+  }
 }
 
 export function isPrimitive(value: any): boolean {


Test patch:
diff --git a/test-dts/defineComponent.test-d.ts b/test-dts/defineComponent.test-d.ts
index cd0b56a..bdd033c 100644
--- a/test-dts/defineComponent.test-d.ts
+++ b/test-dts/defineComponent.test-d.ts
@@ -27,6 +27,7 @@ describe('with object props', () => {
     ggg: 'foo' | 'bar'
     ffff: (a: number, b: string) => { a: boolean }
     validated?: string
+    date: Date
   }
 
   type GT = string & { __brand: unknown }
@@ -96,6 +97,10 @@ describe('with object props', () => {
         // validator requires explicit annotation
         validator: (val: unknown) => val !== '',
       },
+      date: {
+        type: Date,
+        required: true,
+      },
     },
     setup(props) {
       // type assertion. See https://github.com/SamVerschueren/tsd
@@ -116,6 +121,7 @@ describe('with object props', () => {
       expectType<ExpectedProps['hhh']>(props.hhh)
       expectType<ExpectedProps['ffff']>(props.ffff)
       expectType<ExpectedProps['validated']>(props.validated)
+      expectType<ExpectedProps['date']>(props.date)
 
       isNotAnyOrUndefined(props.a)
       isNotAnyOrUndefined(props.b)
diff --git a/test/use.spec.ts b/test/use.spec.ts
index 8e02921..469e2f8 100644
--- a/test/use.spec.ts
+++ b/test/use.spec.ts
@@ -13,7 +13,9 @@ describe('use', () => {
     const localVueTwo = createLocalVue()
     localVueTwo.use(CompositionApi)
 
-    expect('Another instance of vue installed').not.toHaveBeenWarned()
+    expect(
+      '[vue-composition-api] another instance of Vue installed'
+    ).not.toHaveBeenWarned()
   })
 
   it('should warn install in multiple vue', () => {
@@ -28,10 +30,14 @@ describe('use', () => {
 
       // @ts-ignore
       CompositionApi.install(fakeVue)
-      expect('Another instance of vue installed').toHaveBeenWarned()
+      expect(
+        '[vue-composition-api] another instance of Vue installed'
+      ).toHaveBeenWarned()
     } finally {
       Vue.use(CompositionApi)
-      expect('Another instance of vue installed').toHaveBeenWarned()
+      expect(
+        '[vue-composition-api] another instance of Vue installed'
+      ).toHaveBeenWarned()
     }
   })
 
@@ -39,15 +45,15 @@ describe('use', () => {
     const localVueOne = createLocalVue()
     localVueOne.use(CompositionApi)
 
-    expect(() => {
-      // vue prevents the same plugin of being installed, this will create a new plugin instance
-      localVueOne.use({
-        install(v) {
-          CompositionApi.install(v)
-        },
-      })
-    }).toThrowError(
-      'already installed. Vue.use(VueCompositionAPI) should be called only once.'
-    )
+    // vue prevents the same plugin of being installed, this will create a new plugin instance
+    localVueOne.use({
+      install(v) {
+        CompositionApi.install(v)
+      },
+    })
+
+    expect(
+      '[vue-composition-api] already installed. Vue.use(VueCompositionAPI) should be called only once.'
+    ).toHaveBeenWarned()
   })
 })