Types overview
egghead.io lesson 11: More mobx-state-tree Types: map, literal, union, and enumeration
Hosted on egghead.io
egghead.io lesson 17: Create Dynamic Types and use Type Composition to Extract Common Functionality
Hosted on egghead.io
These are the types available in MST. All types can be found in the types namespace, e.g. types.string.
Complex types
types.model(properties, actions)Defines a "class like" type with properties and actions to operate on the object.types.array(type)Declares an array of the specified type.types.map(type)Declares a map of the specified type.
Note that since MST v3 types.array and types.map are wrapped in types.optional by default, with [] and {} set as their default values, respectively.
Primitive types
types.stringtypes.numbertypes.integertypes.floattypes.finitetypes.booleantypes.Datetypes.customcreates a custom primitive type. This is useful to define your own types that map a serialized form one-to-one to an immutable object like a Decimal or Date.
Utility types
types.union(options?: { dispatcher?: (snapshot) => Type, eager?: boolean }, types...)create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function to determine the type. Wheneagerflag is set totrue(default) - the first matching type will be used, if set tofalsethe type check will pass only if exactly 1 type matches.types.optional(type, defaultValue, optionalValues?)marks a value as being optional (in e.g. a model). If a value is not provided/undefined(or set to any of the primitive values passed as an optionaloptionalValuesarray) thedefaultValuewill be used instead. IfdefaultValueis a function, it will be evaluated. This can be used to generate, for example, IDs or timestamps upon creation.types.literal(value)can be used to create a literal type, where the only possible value is specifically that value. This is very powerful in combination withunions. E.g.temperature: types.union(types.literal("hot"), types.literal("cold")).types.enumeration(name?, options: string[])creates an enumeration. This method is a shorthand for a union of string literals. If you are using typescript and want to create a type based on an string enum (e.g.enum Color { ... }) then usetypes.enumeration<Color>("Color", Object.values(Color)), where the"Color"name argument is optional.types.refinement(name?, baseType, (snapshot) => boolean)creates a type that is more specific than the base type, e.g.types.refinement(types.string, value => value.length > 5)to create a type of strings that can only be longer than 5.types.maybe(type)makes a type optional and nullable. The valueundefinedwill be used to represent nullability. Shorthand fortypes.optional(types.union(type, types.literal(undefined)), undefined).types.maybeNull(type)likemaybe, but usesnullto represent the absence of a value.types.nullthe type ofnull.types.undefinedthe type ofundefined.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.types.frozen(subType? | defaultValue?)Accepts any kind of serializable value (both primitive and complex), but assumes that the value itself is immutable and serializable.frozencan be invoked in a few different ways:types.frozen()- behaves the same as types.frozen in MST 2.types.frozen(subType)- provide a valid MST type and frozen will check if the provided data conforms the snapshot for that type. Note that the type will not actually be instantiated, so it can only be used to check the shape of the data. Adding views or actions to SubType would be pointless.types.frozen(someDefaultValue)- provide a primitive value, object or array, and MST will infer the type from that object, and also make it the default value for the field- (Typescript)
types.frozen<TypeScriptType>(...)- provide a typescript type, to help in strongly typing the field (design time only)
types.compose(name?, type1...typeX), creates a new model type by taking a bunch of existing types and combining them into a new one.types.reference(targetType)creates a property that is a reference to another item of the giventargetTypesomewhere in the same tree. See references for more details.types.safeReference(targetType)is like a standard reference, except that it accepts the undefined value by default and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps when the reference it is pointing to gets detached/destroyed. See references for more details.types.snapshotProcessor(type, processors, name?)runs a pre snapshot / post snapshot processor before/after serializing a given type. See known issue withapplySnapshotandpreProcessSnapshotExample:const Todo1 = types.model({ text: types.string }) // in the backend the text type must be null when empty interface BackendTodo { text: string | null } const Todo2 = types.snapshotProcessor(Todo1, { // from snapshot to instance preProcessor(sn: BackendTodo) { return { text: sn.text || ""; } }, // from instance to snapshot postProcessor(sn): BackendTodo { return { text: !sn.text ? null : sn.text } } })
Property types
Property types can only be used as a direct member of a types.model type and not further composed (for now).
types.identifierOnly one such member can exist in atypes.modeland should uniquely identify the object. See identifiers for more details.types.identifierNumberSimilar totypes.identifier. However, during serialization, the identifier value will be parsed from / serialized to a number.