Skip to content

Commit a283e60

Browse files
committed
Merge branch 'master' into next
2 parents 3ddd223 + 9566e63 commit a283e60

File tree

13 files changed

+166
-62
lines changed

13 files changed

+166
-62
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,34 @@
3636

3737
* implement `effectScope` api ([#762](https://github.com/vuejs/composition-api/issues/762)) ([fcadec2](https://github.com/vuejs/composition-api/commit/fcadec2))
3838

39+
<a name="1.0.5"></a>
40+
## [1.0.5](https://github.com/vuejs/composition-api/compare/v1.0.4...v1.0.5) (2021-08-01)
41+
42+
43+
### Bug Fixes
44+
45+
* **function:** properties of function should not disappear. ([#778](https://github.com/vuejs/composition-api/issues/778)) ([68c1a35](https://github.com/vuejs/composition-api/commit/68c1a35))
46+
47+
48+
49+
<a name="1.0.4"></a>
50+
## [1.0.4](https://github.com/vuejs/composition-api/compare/v1.0.3...v1.0.4) (2021-07-22)
51+
52+
53+
### Bug Fixes
54+
55+
* revert module field to `esm.js` version, close [#769](https://github.com/vuejs/composition-api/issues/769) ([4ac545c](https://github.com/vuejs/composition-api/commit/4ac545c))
56+
57+
58+
59+
<a name="1.0.3"></a>
60+
## [1.0.3](https://github.com/vuejs/composition-api/compare/v1.0.2...v1.0.3) (2021-07-18)
61+
62+
63+
### Bug Fixes
64+
65+
* build for mjs and exports all submodules ([69538ee](https://github.com/vuejs/composition-api/commit/69538ee))
66+
3967

4068

4169
<a name="1.0.2"></a>

src/apis/computed.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
noopFn,
66
defineComponentInstance,
77
getVueInternalClasses,
8+
isFunction,
89
} from '../utils'
910
import { getCurrentScopeVM } from './effectScope'
1011

@@ -36,7 +37,7 @@ export function computed<T>(
3637
let getter: ComputedGetter<T>
3738
let setter: ComputedSetter<T> | undefined
3839

39-
if (typeof getterOrOptions === 'function') {
40+
if (isFunction(getterOrOptions)) {
4041
getter = getterOrOptions
4142
} else {
4243
getter = getterOrOptions.get

src/apis/lifecycle.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ const genName = (name: string) => `on${name[0].toUpperCase() + name.slice(1)}`
1111
function createLifeCycle(lifeCyclehook: string) {
1212
return (callback: Function) => {
1313
const vm = currentVMInFn(genName(lifeCyclehook))
14-
if (vm) {
15-
injectHookOption(getVueConstructor(), vm, lifeCyclehook, callback)
16-
}
14+
return (
15+
vm && injectHookOption(getVueConstructor(), vm, lifeCyclehook, callback)
16+
)
1717
}
1818
}
1919

@@ -25,10 +25,12 @@ function injectHookOption(
2525
) {
2626
const options = vm.$options as Record<string, unknown>
2727
const mergeFn = Vue.config.optionMergeStrategies[hook]
28-
options[hook] = mergeFn(options[hook], wrapHookCall(vm, val))
28+
const wrappedHook = wrapHookCall(vm, val)
29+
options[hook] = mergeFn(options[hook], wrappedHook)
30+
return wrappedHook
2931
}
3032

31-
function wrapHookCall(vm: ComponentInstance, fn: Function) {
33+
function wrapHookCall(vm: ComponentInstance, fn: Function): Function {
3234
return (...args: any) => {
3335
let preVm = getCurrentInstance()?.proxy
3436
setCurrentInstance(vm)

src/apis/watch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ export function watch<T = any>(
433433
options?: WatchOptions
434434
): WatchStopHandle {
435435
let callback: WatchCallback<unknown> | null = null
436-
if (typeof cb === 'function') {
436+
if (isFunction(cb)) {
437437
// source watch
438438
callback = cb as WatchCallback<unknown>
439439
} else {

src/install.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { VueConstructor } from 'vue'
22
import { AnyObject } from './types/basic'
3-
import { hasSymbol, hasOwn, isPlainObject, warn } from './utils'
3+
import { isFunction, hasSymbol, hasOwn, isPlainObject, warn } from './utils'
44
import { isRef } from './reactivity'
55
import { setVueConstructor, isVueRegistered } from './runtimeContext'
66
import { mixin } from './mixin'
@@ -67,8 +67,8 @@ export function install(Vue: VueConstructor) {
6767
) {
6868
return function mergedSetupFn(props: any, context: any) {
6969
return mergeData(
70-
typeof parent === 'function' ? parent(props, context) || {} : undefined,
71-
typeof child === 'function' ? child(props, context) || {} : undefined
70+
isFunction(parent) ? parent(props, context) || {} : undefined,
71+
isFunction(child) ? child(props, context) || {} : undefined
7272
)
7373
}
7474
}

src/mixin.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function mixin(Vue: VueConstructor) {
6060
if (!setup) {
6161
return
6262
}
63-
if (typeof setup !== 'function') {
63+
if (!isFunction(setup)) {
6464
if (__DEV__) {
6565
warn(
6666
'The "setup" option should be a function that returns a object in component definitions.',
@@ -74,7 +74,7 @@ export function mixin(Vue: VueConstructor) {
7474
// wrapper the data option, so we can invoke setup before data get resolved
7575
$options.data = function wrappedData() {
7676
initSetup(vm, vm.$props)
77-
return typeof data === 'function'
77+
return isFunction(data)
7878
? (
7979
data as (this: ComponentInstance, x: ComponentInstance) => object
8080
).call(vm, vm)
@@ -124,7 +124,11 @@ export function mixin(Vue: VueConstructor) {
124124
if (!isRef(bindingValue)) {
125125
if (!isReactive(bindingValue)) {
126126
if (isFunction(bindingValue)) {
127+
const copy = bindingValue
127128
bindingValue = bindingValue.bind(vm)
129+
Object.keys(copy).forEach(function (ele) {
130+
bindingValue[ele] = copy[ele]
131+
})
128132
} else if (!isObject(bindingValue)) {
129133
bindingValue = ref(bindingValue)
130134
} else if (hasReactiveArrayChild(bindingValue)) {

src/reactivity/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,11 @@ export { readonly, isReadonly, shallowReadonly } from './readonly'
2222
export { set } from './set'
2323
export { del } from './del'
2424

25-
export type { Ref, ToRefs, UnwrapRef, ShallowUnwrapRef } from './ref'
26-
export type { DeepReadonly } from './readonly'
25+
export type {
26+
Ref,
27+
ToRefs,
28+
UnwrapRef,
29+
UnwrapRefSimple,
30+
ShallowUnwrapRef,
31+
} from './ref'
32+
export type { DeepReadonly, UnwrapNestedRefs } from './readonly'

src/reactivity/readonly.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { reactive, Ref, UnwrapRef } from '.'
1+
import { reactive, Ref, UnwrapRefSimple } from '.'
22
import { isArray, isPlainObject, isObject, warn, proxy } from '../utils'
33
import { readonlySet } from '../utils/sets'
44
import { isReactive, observe } from './reactive'
@@ -33,7 +33,7 @@ export type DeepReadonly<T> = T extends Builtin
3333
: Readonly<T>
3434

3535
// only unwrap nested ref
36-
type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
36+
export type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRefSimple<T>
3737

3838
/**
3939
* **In @vue/composition-api, `reactive` only provides type-level readonly check**

src/reactivity/ref.ts

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,20 @@ export type UnwrapRef<T> = T extends Ref<infer V>
2929
? UnwrapRefSimple<V>
3030
: UnwrapRefSimple<T>
3131

32-
type UnwrapRefSimple<T> = T extends Function | CollectionTypes | BaseTypes | Ref
32+
export type UnwrapRefSimple<T> = T extends
33+
| Function
34+
| CollectionTypes
35+
| BaseTypes
36+
| Ref
3337
? T
3438
: T extends Array<any>
3539
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
3640
: T extends object
37-
? UnwrappedObject<T>
41+
? {
42+
[P in keyof T]: P extends symbol ? T[P] : UnwrapRef<T[P]>
43+
}
3844
: T
3945

40-
// Extract all known symbols from an object
41-
// when unwrapping Object the symbols are not `in keyof`, this should cover all the
42-
// known symbols
43-
type SymbolExtract<T> = (T extends { [Symbol.asyncIterator]: infer V }
44-
? { [Symbol.asyncIterator]: V }
45-
: {}) &
46-
(T extends { [Symbol.hasInstance]: infer V }
47-
? { [Symbol.hasInstance]: V }
48-
: {}) &
49-
(T extends { [Symbol.isConcatSpreadable]: infer V }
50-
? { [Symbol.isConcatSpreadable]: V }
51-
: {}) &
52-
(T extends { [Symbol.iterator]: infer V } ? { [Symbol.iterator]: V } : {}) &
53-
(T extends { [Symbol.match]: infer V } ? { [Symbol.match]: V } : {}) &
54-
(T extends { [Symbol.replace]: infer V } ? { [Symbol.replace]: V } : {}) &
55-
(T extends { [Symbol.search]: infer V } ? { [Symbol.search]: V } : {}) &
56-
(T extends { [Symbol.species]: infer V } ? { [Symbol.species]: V } : {}) &
57-
(T extends { [Symbol.split]: infer V } ? { [Symbol.split]: V } : {}) &
58-
(T extends { [Symbol.toPrimitive]: infer V }
59-
? { [Symbol.toPrimitive]: V }
60-
: {}) &
61-
(T extends { [Symbol.toStringTag]: infer V }
62-
? { [Symbol.toStringTag]: V }
63-
: {}) &
64-
(T extends { [Symbol.unscopables]: infer V }
65-
? { [Symbol.unscopables]: V }
66-
: {})
67-
68-
type UnwrappedObject<T> = { [P in keyof T]: UnwrapRef<T[P]> } & SymbolExtract<T>
69-
7046
interface RefOption<T> {
7147
get(): T
7248
set?(x: T): void

src/runtimeContext.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import type { VueConstructor, VNode } from 'vue'
22
import { ComponentInstance, Data } from './component'
3-
import { assert, hasOwn, warn, proxy, UnionToIntersection } from './utils'
3+
import {
4+
assert,
5+
hasOwn,
6+
warn,
7+
proxy,
8+
UnionToIntersection,
9+
isFunction,
10+
} from './utils'
411

512
let vueDependency: VueConstructor | undefined = undefined
613

@@ -26,7 +33,7 @@ let currentInstanceTracking = true
2633
const PluginInstalledFlag = '__composition_api_installed__'
2734

2835
function isVue(obj: any): obj is VueConstructor {
29-
return obj && typeof obj === 'function' && obj.name === 'Vue'
36+
return obj && isFunction(obj) && obj.name === 'Vue'
3037
}
3138

3239
export function isPluginInstalled() {

test-dts/ref.test-d.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,42 @@ bailType(el)
7878
function withSymbol() {
7979
const customSymbol = Symbol()
8080
const obj = {
81-
[Symbol.asyncIterator]: { a: 1 },
82-
[Symbol.unscopables]: { b: '1' },
83-
[customSymbol]: { c: [1, 2, 3] },
81+
[Symbol.asyncIterator]: ref(1),
82+
[Symbol.hasInstance]: { a: ref('a') },
83+
[Symbol.isConcatSpreadable]: { b: ref(true) },
84+
[Symbol.iterator]: [ref(1)],
85+
[Symbol.match]: new Set<Ref<number>>(),
86+
[Symbol.matchAll]: new Map<number, Ref<string>>(),
87+
[Symbol.replace]: { arr: [ref('a')] },
88+
[Symbol.search]: { set: new Set<Ref<number>>() },
89+
[Symbol.species]: { map: new Map<number, Ref<string>>() },
90+
[Symbol.split]: new WeakSet<Ref<boolean>>(),
91+
[Symbol.toPrimitive]: new WeakMap<Ref<boolean>, string>(),
92+
[Symbol.toStringTag]: { weakSet: new WeakSet<Ref<boolean>>() },
93+
[Symbol.unscopables]: { weakMap: new WeakMap<Ref<boolean>, string>() },
94+
[customSymbol]: { arr: [ref(1)] },
8495
}
8596

8697
const objRef = ref(obj)
8798

88-
expectType<{ a: number }>(objRef.value[Symbol.asyncIterator])
89-
expectType<{ b: string }>(objRef.value[Symbol.unscopables])
90-
expectType<{ c: Array<number> }>(objRef.value[customSymbol])
99+
expectType<Ref<number>>(objRef.value[Symbol.asyncIterator])
100+
expectType<{ a: Ref<string> }>(objRef.value[Symbol.hasInstance])
101+
expectType<{ b: Ref<boolean> }>(objRef.value[Symbol.isConcatSpreadable])
102+
expectType<Ref<number>[]>(objRef.value[Symbol.iterator])
103+
expectType<Set<Ref<number>>>(objRef.value[Symbol.match])
104+
expectType<Map<number, Ref<string>>>(objRef.value[Symbol.matchAll])
105+
expectType<{ arr: Ref<string>[] }>(objRef.value[Symbol.replace])
106+
expectType<{ set: Set<Ref<number>> }>(objRef.value[Symbol.search])
107+
expectType<{ map: Map<number, Ref<string>> }>(objRef.value[Symbol.species])
108+
expectType<WeakSet<Ref<boolean>>>(objRef.value[Symbol.split])
109+
expectType<WeakMap<Ref<boolean>, string>>(objRef.value[Symbol.toPrimitive])
110+
expectType<{ weakSet: WeakSet<Ref<boolean>> }>(
111+
objRef.value[Symbol.toStringTag]
112+
)
113+
expectType<{ weakMap: WeakMap<Ref<boolean>, string> }>(
114+
objRef.value[Symbol.unscopables]
115+
)
116+
expectType<{ arr: Ref<number>[] }>(objRef.value[customSymbol])
91117
}
92118

93119
withSymbol()

test/setup.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,4 +1193,30 @@ describe('setup', () => {
11931193
const vm = new Vue(Constructor).$mount()
11941194
expect(vm.proxy).toBe(originalProxy)
11951195
})
1196+
1197+
// test #687
1198+
it('properties of function should not disappear', () => {
1199+
Vue.component('todo', {
1200+
template: '<div/>',
1201+
props: ['testFn'],
1202+
setup(props) {
1203+
expect(props.testFn.a).toBe(2)
1204+
},
1205+
})
1206+
1207+
const vm = new Vue({
1208+
template: `
1209+
<div>
1210+
<todo :testFn="testFn"></todo>
1211+
</div>
1212+
`,
1213+
setup() {
1214+
const testFn = () => {
1215+
console.log(1)
1216+
}
1217+
testFn.a = 2
1218+
return { testFn }
1219+
},
1220+
}).$mount()
1221+
})
11961222
})

test/v3/reactivity/ref.spec.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,44 @@ describe('reactivity/ref', () => {
167167
it('should keep symbols', () => {
168168
const customSymbol = Symbol()
169169
const obj = {
170-
[Symbol.asyncIterator]: { a: 1 },
171-
[Symbol.unscopables]: { b: '1' },
172-
[customSymbol]: { c: [1, 2, 3] },
170+
[Symbol.asyncIterator]: ref(1),
171+
[Symbol.hasInstance]: { a: ref('a') },
172+
[Symbol.isConcatSpreadable]: { b: ref(true) },
173+
[Symbol.iterator]: [ref(1)],
174+
[Symbol.match]: new Set<Ref<number>>(),
175+
[Symbol.matchAll]: new Map<number, Ref<string>>(),
176+
[Symbol.replace]: { arr: [ref('a')] },
177+
[Symbol.search]: { set: new Set<Ref<number>>() },
178+
[Symbol.species]: { map: new Map<number, Ref<string>>() },
179+
[Symbol.split]: new WeakSet<Ref<boolean>>(),
180+
[Symbol.toPrimitive]: new WeakMap<Ref<boolean>, string>(),
181+
[Symbol.toStringTag]: { weakSet: new WeakSet<Ref<boolean>>() },
182+
[Symbol.unscopables]: { weakMap: new WeakMap<Ref<boolean>, string>() },
183+
[customSymbol]: { arr: [ref(1)] },
173184
}
174185

175186
const objRef = ref(obj)
176187

177-
expect(objRef.value[Symbol.asyncIterator]).toBe(obj[Symbol.asyncIterator])
178-
expect(objRef.value[Symbol.unscopables]).toBe(obj[Symbol.unscopables])
179-
expect(objRef.value[customSymbol]).toStrictEqual(obj[customSymbol])
188+
const keys: (keyof typeof obj)[] = [
189+
Symbol.asyncIterator,
190+
Symbol.hasInstance,
191+
Symbol.isConcatSpreadable,
192+
Symbol.iterator,
193+
Symbol.match,
194+
Symbol.matchAll,
195+
Symbol.replace,
196+
Symbol.search,
197+
Symbol.species,
198+
Symbol.split,
199+
Symbol.toPrimitive,
200+
Symbol.toStringTag,
201+
Symbol.unscopables,
202+
customSymbol,
203+
]
204+
205+
keys.forEach((key) => {
206+
expect(objRef.value[key]).toStrictEqual(obj[key])
207+
})
180208
})
181209

182210
test('unref', () => {

0 commit comments

Comments
 (0)