forked from mobxjs/mobx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextendobservable.ts
More file actions
103 lines (98 loc) · 3.73 KB
/
Copy pathextendobservable.ts
File metadata and controls
103 lines (98 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {
CreateObservableOptions,
asCreateObservableOptions,
asObservableObject,
computedDecorator,
deepDecorator,
endBatch,
fail,
invariant,
isComputed,
isObservable,
isObservableMap,
refDecorator,
startBatch,
initializeInstance
} from "../internal"
import { IObservableDecorator } from "./observabledecorator"
export function extendObservable<A extends Object, B extends Object>(
target: A,
properties?: B,
decorators?: { [K in keyof B]?: Function },
options?: CreateObservableOptions
): A & B {
if (process.env.NODE_ENV !== "production") {
invariant(
arguments.length >= 2 && arguments.length <= 4,
"'extendObservable' expected 2-4 arguments"
)
invariant(
typeof target === "object",
"'extendObservable' expects an object as first argument"
)
invariant(
!isObservableMap(target),
"'extendObservable' should not be used on maps, use map.merge instead"
)
}
options = asCreateObservableOptions(options)
const defaultDecorator = getDefaultDecoratorFromObjectOptions(options)
initializeInstance(target) // Fixes #1740
asObservableObject(target, options.name, defaultDecorator.enhancer) // make sure object is observable, even without initial props
if (properties)
extendObservableObjectWithProperties(target, properties, decorators, defaultDecorator)
return target as any
}
export function getDefaultDecoratorFromObjectOptions(
options: CreateObservableOptions
): IObservableDecorator {
return options.defaultDecorator || (options.deep === false ? refDecorator : deepDecorator)
}
export function extendObservableObjectWithProperties(
target,
properties,
decorators,
defaultDecorator
) {
if (process.env.NODE_ENV !== "production") {
invariant(
!isObservable(properties),
"Extending an object with another observable (object) is not supported. Please construct an explicit propertymap, using `toJS` if need. See issue #540"
)
if (decorators)
for (let key in decorators)
if (!(key in properties!))
fail(`Trying to declare a decorator for unspecified property '${key}'`)
}
startBatch()
try {
for (let key in properties) {
const descriptor = Object.getOwnPropertyDescriptor(properties, key)!
if (process.env.NODE_ENV !== "production") {
if (Object.getOwnPropertyDescriptor(target, key))
fail(
`'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead. The property '${key}' already exists on '${target}'`
)
if (isComputed(descriptor.value))
fail(
`Passing a 'computed' as initial property value is no longer supported by extendObservable. Use a getter or decorator instead`
)
}
const decorator =
decorators && key in decorators
? decorators[key]
: descriptor.get
? computedDecorator
: defaultDecorator
if (process.env.NODE_ENV !== "production" && typeof decorator !== "function")
fail(`Not a valid decorator for '${key}', got: ${decorator}`)
const resultDescriptor = decorator!(target, key, descriptor, true)
if (
resultDescriptor // otherwise, assume already applied, due to `applyToInstance`
)
Object.defineProperty(target, key, resultDescriptor)
}
} finally {
endBatch()
}
}