Repository: vuejs/composition-api
Pull request #596 (2020-11-23 12:18:43)

feat: add warn
Pretty much what was discussed at https://github.com/antfu/vue-demi/pull/19


Patch:
diff --git a/README.md b/README.md
index ae736fa..a85a011 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Vue 2 plugin for **Composition API**
 [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)](https://github.com/vuejs/composition-api/actions?query=workflow%3A%22Build+%26+Test%22)
 [![Minzipped size](https://badgen.net/bundlephobia/minzip/@vue/composition-api)](https://bundlephobia.com/result?p=@vue/composition-api)
 
-English | [中文](./README.zh-CN.md) ・ [**Composition API Docs**](https://composition-api.vuejs.org/)
+English | [中文](./README.zh-CN.md) ・ [**Composition API Docs**](https://v3.vuejs.org/guide/composition-api-introduction.html)
 
 ## Installation
 
diff --git a/README.zh-CN.md b/README.zh-CN.md
index f94bb80..173af06 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -5,7 +5,7 @@
 [![npm](https://img.shields.io/npm/v/@vue/composition-api)](https://www.npmjs.com/package/@vue/composition-api)
 [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)](https://github.com/vuejs/composition-api/actions?query=workflow%3A%22Build+%26+Test%22)
 
-[English](./README.md) | 中文 ・ [**组合式 API 文档**](https://composition-api.vuejs.org/zh)
+[English](./README.md) | 中文 ・ [**组合式 API 文档**](https://v3.cn.vuejs.org/guide/composition-api-introduction.html)
 
 ## 安装
 
diff --git a/src/apis/index.ts b/src/apis/index.ts
index bf2e31e..d182102 100644
--- a/src/apis/index.ts
+++ b/src/apis/index.ts
@@ -30,3 +30,4 @@ export { useCSSModule } from './useCssModule'
 export { createApp } from './createApp'
 export { nextTick } from './nextTick'
 export { createElement as h } from './createElement'
+export { warn } from './warn'
diff --git a/src/apis/warn.ts b/src/apis/warn.ts
new file mode 100644
index 0000000..2bb5236
--- /dev/null
+++ b/src/apis/warn.ts
@@ -0,0 +1,12 @@
+import { getCurrentInstance } from '../runtimeContext'
+import { warn as vueWarn } from '../utils'
+
+/**
+ * Displays a warning message (using console.error) with a stack trace if the
+ * function is called inside of active component.
+ *
+ * @param message warning message to be displayed
+ */
+export function warn(message: string) {
+  vueWarn(message, getCurrentInstance())
+}
diff --git a/src/component/componentOptions.ts b/src/component/componentOptions.ts
index 5f0f150..c78decf 100644
--- a/src/component/componentOptions.ts
+++ b/src/component/componentOptions.ts
@@ -5,10 +5,27 @@ import { ComponentInstance, ComponentRenderProxy } from './componentProxy'
 
 export interface SetupContext {
   readonly attrs: Data
-  readonly slots: { [key: string]: (...args: any[]) => VNode[] }
+  readonly slots: Readonly<{ [key in string]?: (...args: any[]) => VNode[] }>
+
+  /**
+   * @deprecated not avaliable in Vue 3
+   */
   readonly parent: ComponentInstance | null
+
+  /**
+   * @deprecated not avaliable in Vue 3
+   */
   readonly root: ComponentInstance
-  readonly listeners: { [key: string]: Function }
+
+  /**
+   * @deprecated not avaliable in Vue 3
+   */
+  readonly listeners: { [key in string]?: Function }
+
+  /**
+   * @deprecated not avaliable in Vue 3
+   */
+  readonly refs: Data
 
   emit(event: string, ...args: any[]): void
 }
diff --git a/src/env.d.ts b/src/env.d.ts
index 161e9a6..8e36248 100644
--- a/src/env.d.ts
+++ b/src/env.d.ts
@@ -19,7 +19,7 @@ declare module 'vue/types/vue' {
   interface VueConstructor {
     observable<T>(x: any): T
     util: {
-      warn(msg: string, vm?: Vue)
+      warn(msg: string, vm?: Vue | null)
       defineReactive(
         obj: Object,
         key: string,
diff --git a/src/mixin.ts b/src/mixin.ts
index 17fe2e8..0e67e4b 100644
--- a/src/mixin.ts
+++ b/src/mixin.ts
@@ -88,6 +88,7 @@ export function mixin(Vue: VueConstructor) {
     def(props, '__ob__', createObserver())
 
     // resolve scopedSlots and slots to functions
+    // @ts-expect-error
     resolveScopedSlots(vm, ctx.slots)
 
     let binding: ReturnType<SetupFunction<Data, Data>> | undefined | null
@@ -102,6 +103,7 @@ export function mixin(Vue: VueConstructor) {
       const bindingFunc = binding
       // keep currentInstance accessible for createElement
       vm.$options.render = () => {
+        // @ts-expect-error
         resolveScopedSlots(vm, ctx.slots)
         return activateCurrentInstance(vm, () => bindingFunc())
       }
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 0bffd6d..2c4f4fc 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -83,7 +83,7 @@ export function isUndef(v: any): boolean {
   return v === undefined || v === null
 }
 
-export function warn(msg: string, vm?: Vue) {
+export function warn(msg: string, vm?: Vue | null) {
   Vue.util.warn(msg, vm)
 }
 


Test patch:
diff --git a/test/apis/warn.spec.js b/test/apis/warn.spec.js
new file mode 100644
index 0000000..9ceb5fa
--- /dev/null
+++ b/test/apis/warn.spec.js
@@ -0,0 +1,32 @@
+const Vue = require('vue/dist/vue.common.js')
+const { warn: apiWarn } = require('../../src')
+
+describe('api/warn', () => {
+  beforeEach(() => {
+    warn = jest.spyOn(global.console, 'error').mockImplementation(() => null)
+  })
+  afterEach(() => {
+    warn.mockRestore()
+  })
+
+  it('can be called inside a component', () => {
+    new Vue({
+      setup() {
+        apiWarn('warned')
+      },
+      template: `<div></div>`,
+    }).$mount()
+
+    expect(warn).toHaveBeenCalledTimes(1)
+    expect(warn.mock.calls[0][0]).toMatch(
+      /\[Vue warn\]: warned[\s\S]*\(found in <Root>\)/
+    )
+  })
+
+  it('can be called outside a component', () => {
+    apiWarn('warned')
+
+    expect(warn).toHaveBeenCalledTimes(1)
+    expect(warn).toHaveBeenCalledWith('[Vue warn]: warned')
+  })
+})