Skip to content

Commit

Permalink
Made map / array values optional for model properties, implements #906
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Jul 4, 2018
1 parent 85efcd2 commit a8c7c60
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 32 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Improvements

* It is no longer necessary to wrap `types.map` or `types.array` in `types.optional` when used in a model type, they are now optional by default when used as property type.
* Introduced `setLivelynessChecking("warn" | "ignore" | "error")`
// TODO: add actual numbers
* Significantly improved the performance of constructing MST trees. Significantly reduced the memory footprint of MST. Big shoutout to the relentless effort by [k-g-a](https://github.com/k-g-a) to optimize all the things! See [#845](https://github.com/mobxjs/mobx-state-tree/issues/845) for details.
Expand Down
33 changes: 27 additions & 6 deletions packages/mobx-state-tree/src/types/complex-types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
_getAdministration,
isComputedProp,
computed,
set
set,
IObservableArray
} from "mobx"
import {
fail,
Expand Down Expand Up @@ -49,7 +50,12 @@ import {
IAnyType,
Union,
Late,
OptionalValue
OptionalValue,
isMapType,
isArrayType,
IMSTMap,
MapType,
ArrayType
} from "../../internal"

const PRE_PROCESS_SNAPSHOT = "preProcessSnapshot"
Expand Down Expand Up @@ -84,9 +90,17 @@ export type ModelPropertiesDeclarationToProperties<T extends ModelPropertiesDecl
? IType<boolean | undefined, boolean, boolean> & { flags: TypeFlags.Optional }
: T[K] extends Date
? IType<number | undefined, number, Date> & { flags: TypeFlags.Optional }
: T[K] extends IType<infer C, infer S, infer T> & { flags: TypeFlags.Optional }
? IType<C, S, T> & { flags: TypeFlags.Optional }
: T[K] extends IType<infer C, infer S, infer T> ? IType<C, S, T> : never
: T[K] extends (IComplexType<
any,
any,
IMSTMap<any, any, any> | IObservableArray<any>
>)
? T[K] & { flags: TypeFlags.Optional }
: T[K] extends IType<any, any, any> & {
flags: TypeFlags.Optional
}
? T[K] & { flags: TypeFlags.Optional }
: T[K] extends IType<any, any, any> ? T[K] : never
}

export type OptionalPropertyTypes = ModelPrimitive | { flags: TypeFlags.Optional }
Expand Down Expand Up @@ -205,6 +219,13 @@ function toPropertiesObject<T>(declaredProps: ModelPropertiesDeclaration): Model
return Object.assign({}, props, {
[key]: optional(getPrimitiveFactoryFromValue(value), value)
})
// map defaults to empty object automatically for models
} else if (value instanceof MapType) {
return Object.assign({}, props, {
[key]: optional(value, {})
})
} else if (value instanceof ArrayType) {
return Object.assign({}, props, { [key]: optional(value, []) })
// its already a type
} else if (isType(value)) {
return props
Expand Down Expand Up @@ -695,7 +716,7 @@ export function compose(...args: any[]): any {
.named(typeName)
}

export function isObjectType(type: any): type is ModelType<any, any> {
export function isModelType(type: any): type is ModelType<any, any> {
return isType(type) && (type.flags & TypeFlags.Object) > 0
}

Expand Down
4 changes: 2 additions & 2 deletions packages/mobx-state-tree/test/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ test("items should be reconciled correctly when splicing - 1", () => {
d = Task.create({ x: "d" })
const store = types
.model({
todos: types.optional(types.array(Task), [])
todos: types.array(Task)
})
.create({
todos: [a]
Expand Down Expand Up @@ -295,7 +295,7 @@ test("it correctly reconciliate when swapping", () => {
test("it correctly reconciliate when swapping using snapshots", () => {
const Task = types.model("Task", {})
const Store = types.model({
todos: types.optional(types.array(Task), [])
todos: types.array(Task)
})
const s = Store.create()
unprotect(s)
Expand Down
2 changes: 1 addition & 1 deletion packages/mobx-state-tree/test/late.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ test("late should describe correctly circular references", () => {
const Node = types.model("Node", {
childs: types.array(types.late(() => Node))
})
expect(Node.describe()).toEqual("{ childs: Node[] }")
expect(Node.describe()).toEqual("{ childs: Node[]? }")
})
test("should typecheck", () => {
const NodeObject = types.model("NodeObject", {
Expand Down
2 changes: 1 addition & 1 deletion packages/mobx-state-tree/test/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ test("it should not throw when removing a non existing item from a map", () => {
expect(() => {
const AppModel = types
.model({
myMap: types.optional(types.map(types.number), {})
myMap: types.map(types.number)
})
.actions(self => {
function something() {
Expand Down
44 changes: 24 additions & 20 deletions packages/mobx-state-tree/test/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ test("it should apply snapshots", () => {
expect(getSnapshot(doc)).toEqual({ to: "universe" })
})
test("it should apply and accept null value for types.maybe(complexType)", () => {
const Item = types.model({
const Item = types.model("Item", {
value: types.string
})
const Model = types.model({
const Model = types.model("Model", {
item: types.maybe(Item)
})
const myModel = Model.create()
Expand Down Expand Up @@ -462,7 +462,7 @@ test("it should check the type correctly", () => {
})

if (process.env.NODE_ENV !== "production") {
test("it should require complex fields to be present", () => {
test("complex map / array values are optional by default", () => {
expect(
types
.model({
Expand All @@ -475,36 +475,40 @@ if (process.env.NODE_ENV !== "production") {
.model({
todo: types.model({})
})
.create()
.create({} as any)
).toThrow()
expect(
types
.model({
todo: types.array(types.string)
})
.is({})
).toBe(false) // TBD: or true?
expect(() =>
types
.model({
todo: types.array(types.string)
})
.create()
).toThrow()
).toBe(true) // TBD: or true?
expect(
getSnapshot(
types
.model({
todo: types.array(types.string)
})
.create({})
)
).toEqual({ todo: [] })
expect(
types
.model({
todo: types.map(types.string)
})
.is({})
).toBe(false)
expect(() =>
types
.model({
todo: types.map(types.string)
})
.create()
).toThrow()
).toBe(true)
expect(
getSnapshot(
types
.model({
todo: types.map(types.string)
})
.create({})
)
).toEqual({ todo: {} })
})
}
// === VIEW FUNCTIONS ===
Expand Down
2 changes: 1 addition & 1 deletion packages/mobx-state-tree/test/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ test("it should resolve refs over late types", () => {
}))
const Store = types.model({
books: types.array(Book),
entries: types.optional(types.array(BookEntry), [])
entries: types.array(BookEntry)
})
const s = Store.create({
books: [{ id: "3", price: 2 }]
Expand Down
2 changes: 1 addition & 1 deletion packages/mobx-state-tree/test/reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Model = types
.model({
isPerson: false,
users: types.optional(types.map(User), {}),
dogs: types.optional(types.array(User), []),
dogs: types.array(User),
user: types.maybe(types.late(() => User))
})
.volatile(self => ({
Expand Down

0 comments on commit a8c7c60

Please sign in to comment.