Skip to content

Commit 3202d70

Browse files
committed
compose can now directly compose model types as well
1 parent 9ec8144 commit 3202d70

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ These are the types available in MST. All types can be found in the `types` name
529529
* `types.maybe(type)` makes a type optional and nullable, shorthand for `types.optional(types.union(type, types.literal(null)), null)`.
530530
* `types.late(() => type)` can be used to create recursive or circular types, or types that are spread over files in such a way that circular dependencies between files would be an issue otherwise.
531531
* `types.frozen` Accepts any kind of serializable value (both primitive and complex), but assumes that the value itself is immutable.
532+
* `types.compose(name?, type1...typeX)`, creates a new model type by taking a bunch of existing types and combining it into a new one
532533
* `types.compose(name?, baseType, props, volatileState?, actions?)`, creates a new model type by taking an existing type and introducing additional properties, state and actions
533534

534535
## Property types

src/types/complex-types/object.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,26 @@ export function model(...args: any[]) {
273273
return new ObjectType(name, props, volatileState, actions)
274274
}
275275

276+
export function compose<T1, S1, A1, T2, S2, A2>(
277+
name: string,
278+
t1: IModelType<T1, S1, A1>,
279+
t2: IModelType<T2, S2, A2>
280+
): IModelType<T1 & T2, S1 & S2, A1 & A2>
281+
export function compose<T1, S1, A1, T2, S2, A2>(
282+
t1: IModelType<T1, S1, A1>,
283+
t2: IModelType<T2, S2, A2>
284+
): IModelType<T1 & T2, S1 & S2, A1 & A2>
285+
export function compose<T1, S1, A1, T2, S2, A2>(
286+
name: string,
287+
t1: IModelType<T1, S1, A1>,
288+
t2: IModelType<T2, S2, A2>
289+
): IModelType<T1 & T2, S1 & S2, A1 & A2>
290+
export function compose<T1, S1, A1, T2, S2, A2, T3, S3, A3>(
291+
name: string,
292+
t1: IModelType<T1, S1, A1>,
293+
t2: IModelType<T2, S2, A2>,
294+
t3: IModelType<T3, S3, A3>
295+
): IModelType<T1 & T2 & T3, S1 & S2 & S3, A1 & A2 & A3> // ...and so forth...
276296
export function compose<BASE_T, BASE_S, BASE_A, T, S, A>(
277297
baseType: IModelType<BASE_T, BASE_S, BASE_A>,
278298
properties: IModelProperties<T> & ThisType<T & BASE_T>
@@ -306,8 +326,21 @@ export function compose<BASE_T, BASE_S, BASE_A, T, S, A>(
306326
volatileState: IModelVolatileState<S> & ThisType<BASE_T & T & BASE_S & S>,
307327
operations: A & ThisType<BASE_T & T & BASE_S & S & BASE_A & A>
308328
): IModelType<BASE_T & T, BASE_S & S, BASE_A & A>
329+
export function compose<T1, S1, A1, T2, S2, A2, T3, S3, A3>(
330+
t1: IModelType<T1, S1, A1>,
331+
t2: IModelType<T2, S2, A2>,
332+
t3: IModelType<T3, S3, A3>
333+
): IModelType<T1 & T2 & T3, S1 & S2 & S3, A1 & A2 & A3> // ...and so forth...
309334
export function compose(...args: any[]) {
310335
const typeName = typeof args[0] === "string" ? args.shift() : "AnonymousModel"
336+
337+
if (args.every(arg => isType(arg))) {
338+
// compose types
339+
return (args as IModelType<any, any, any>[]).reduce((prev, cur) =>
340+
compose(typeName, prev, cur.properties, cur.state, cur.actions)
341+
)
342+
}
343+
311344
const baseType = args.shift()
312345
const props = args.shift() || fail("types.compose must specify properties or `{}`")
313346
const volatileState = (args.length > 1 && args.shift()) || {}

test/object.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ test("it should compose factories with computed properties", t => {
305305
t.is(typeof store.setHeight, "function")
306306
})
307307

308+
test("it should compose multiple types with computed properties", t => {
309+
const { ComputedFactory2, ColorFactory } = createTestFactories()
310+
const ComposedFactory = types.compose(ColorFactory, ComputedFactory2)
311+
const store = ComposedFactory.create({ props: { width: 100, height: 200 } })
312+
t.deepEqual(getSnapshot(store), { props: { width: 100, height: 200 }, color: "#FFFFFF" })
313+
t.is(store.area, 20000)
314+
t.is(typeof store.setWidth, "function")
315+
t.is(typeof store.setHeight, "function")
316+
})
317+
308318
test("methods get overridden by compose", t => {
309319
const A = types.model(
310320
{

0 commit comments

Comments
 (0)