Skip to content

Commit b379765

Browse files
Merge pull request #169 from cpunion/extend-with-getter
Make types.extend supports getter
2 parents 6797a68 + 5c77a2c commit b379765

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

src/types/complex-types/object.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
nothing,
1111
extend as extendObject,
12+
extendKeepGetter,
1213
fail, identity,
1314
isPrimitive,
1415
hasOwnProperty,
@@ -250,6 +251,12 @@ function getObjectFactoryBaseModel(item: any) {
250251
return isObjectFactory(type) ? (type as ObjectType).baseModel : {}
251252
}
252253

254+
function getObjectFactoryBaseActions(item: any) {
255+
let type = isType(item) ? item : getType(item)
256+
257+
return isObjectFactory(type) ? (type as ObjectType).baseActions : {}
258+
}
259+
253260
export function extend<A, B, AA, BA>(name: string, a: IModelType<A, AA>, b: IModelType<B, BA>): IModelType<A & B, AA & BA>
254261
export function extend<A, B, C, AA, BA, CA>(name: string, a: IModelType<A, AA>, b: IModelType<B, BA>, c: IModelType<C, CA>): IModelType<A & B & C, AA & BA & CA>
255262
export function extend<A, B, AA, BA>(a: IModelType<A, AA>, b: IModelType<B, BA>): IModelType<A & B, AA & BA>
@@ -258,11 +265,9 @@ export function extend(...args: any[]) {
258265
console.warn("[mobx-state-tree] `extend` is an experimental feature and it's behavior will probably change in the future")
259266
const baseFactories = typeof args[0] === "string" ? args.slice(1) : args
260267
const factoryName = typeof args[0] === "string" ? args[0] : baseFactories.map(f => f.name).join("_")
261-
262-
return model(
263-
factoryName,
264-
extendObject.apply(null, [{}].concat(baseFactories.map(getObjectFactoryBaseModel)))
265-
)
268+
const properties = extendKeepGetter.apply(null, [{}].concat(baseFactories.map(getObjectFactoryBaseModel)))
269+
const actions = extendObject.apply(null, [{}].concat(baseFactories.map(getObjectFactoryBaseActions)))
270+
return model(factoryName, properties, actions)
266271
}
267272

268273
export function isObjectFactory(type: any): boolean {

src/utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@ export function extend(a: any, ...b: any[]) {
2929
return a
3030
}
3131

32+
export function extendKeepGetter<A, B>(a: A, b: B): A & B
33+
export function extendKeepGetter<A, B, C>(a: A, b: B, c: C): A & B & C
34+
export function extendKeepGetter<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D
35+
export function extendKeepGetter(a: any, ...b: any[]): any
36+
export function extendKeepGetter(a: any, ...b: any[]) {
37+
for (let i = 0; i < b.length; i++) {
38+
const current = b[i]
39+
for (let key in current) {
40+
const descriptor = Object.getOwnPropertyDescriptor(current, key)
41+
if ("get" in descriptor) {
42+
Object.defineProperty(a, key, descriptor)
43+
continue
44+
}
45+
a[key] = current[key]
46+
}
47+
}
48+
return a
49+
}
50+
3251
export function isPlainObject(value: any) {
3352
if (value === null || typeof value !== "object")
3453
return false

test/object.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ const createTestFactories = () => {
2929
}
3030
})
3131

32+
const ComputedFactory2 = types.model({
33+
props: types.map(types.number),
34+
get area(){
35+
return this.props.get('width') * this.props.get('height')
36+
}
37+
}, {
38+
setWidth(value) {
39+
this.props.set('width', value)
40+
},
41+
setHeight(value) {
42+
this.props.set('height', value)
43+
}
44+
})
45+
3246
const BoxFactory = types.model({
3347
width: 0,
3448
height: 0
@@ -38,7 +52,7 @@ const createTestFactories = () => {
3852
color: "#FFFFFF"
3953
})
4054

41-
return {Factory, ComputedFactory, BoxFactory, ColorFactory}
55+
return {Factory, ComputedFactory, ComputedFactory2, BoxFactory, ColorFactory}
4256
}
4357

4458
// === FACTORY TESTS ===
@@ -251,6 +265,16 @@ test("it should compose factories", (t) => {
251265
t.deepEqual(getSnapshot(ComposedFactory.create()), {width: 0, height: 0, color: "#FFFFFF"})
252266
})
253267

268+
test("it should compose factories with computed properties", (t) => {
269+
const {ComputedFactory2, ColorFactory} = createTestFactories()
270+
const ComposedFactory = types.extend(ColorFactory, ComputedFactory2)
271+
const store = ComposedFactory.create({props: {width: 100, height: 200}})
272+
t.deepEqual(getSnapshot(store), {props: {width: 100, height: 200}, color: "#FFFFFF"})
273+
t.is(store.area, 20000)
274+
t.is(typeof store.setWidth, 'function')
275+
t.is(typeof store.setHeight, 'function')
276+
})
277+
254278

255279
// === TYPE CHECKS ===
256280
test("it should check the type correctly", (t) => {

0 commit comments

Comments
 (0)