Core functionality for creating and managing observable state that automatically tracks dependencies and triggers reactions when changed. MobX provides several approaches for creating observables, from explicit decoration to automatic detection.
Creates observables from various data types including primitives, objects, arrays, Maps, and Sets.
/**
* Creates observable state from the provided value
* @param value - Value to make observable (primitive, object, array, Map, Set)
* @returns Observable version of the input value
*/
function observable<T>(value: T): T;Usage Examples:
import { observable } from "mobx";
// Observable primitive
const count = observable.box(0);
console.log(count.get()); // 0
count.set(1);
// Observable object
const person = observable({
name: "Alice",
age: 25
});
person.name = "Bob"; // Triggers reactions
// Observable array
const todos = observable([
{ text: "Learn MobX", completed: false }
]);
todos.push({ text: "Build app", completed: false });
// Observable Map
const userMap = observable.map([
["user1", { name: "Alice" }],
["user2", { name: "Bob" }]
]);
userMap.set("user3", { name: "Charlie" });
// Observable Set
const tags = observable.set(["frontend", "react"]);
tags.add("mobx");Specialized factory methods for creating different types of observables with specific behaviors.
interface IObservableFactory {
/** Creates observable box for primitive values */
box<T>(value: T, options?: CreateObservableOptions): IObservableValue<T>;
/** Creates observable object with specified decorators */
object<T extends object>(
props: T,
decorators?: AnnotationsMap<T>,
options?: CreateObservableOptions
): T;
/** Creates observable array */
array<T>(
initialValues?: T[],
options?: CreateObservableOptions
): IObservableArray<T>;
/** Creates observable Map */
map<K, V>(
initialValues?: IObservableMapInitialValues<K, V>,
options?: CreateObservableOptions
): ObservableMap<K, V>;
/** Creates observable Set */
set<T>(
initialValues?: IObservableSetInitialValues<T>,
options?: CreateObservableOptions
): ObservableSet<T>;
/** Creates shallow observable (only top level) */
ref: Annotation;
/** Creates shallow observable decorator */
shallow: Annotation;
/** Creates structural equality observable */
struct: Annotation;
}Explicitly defines which properties should be observable in existing objects, providing full control over observable behavior.
/**
* Makes properties of an existing object observable
* @param target - Object to make observable
* @param annotations - Map defining which properties should be observable/computed/action
* @param options - Configuration options
* @returns The target object with observable properties
*/
function makeObservable<T extends object>(
target: T,
annotations?: AnnotationsMap<T>,
options?: MakeObservableOptions
): T;Usage Examples:
import { makeObservable, observable, computed, action } from "mobx";
class TodoStore {
todos = [];
filter = "all";
constructor() {
makeObservable(this, {
todos: observable,
filter: observable,
completedCount: computed,
addTodo: action,
setFilter: action
});
}
get completedCount() {
return this.todos.filter(todo => todo.completed).length;
}
addTodo(text) {
this.todos.push({ text, completed: false });
}
setFilter(filter) {
this.filter = filter;
}
}Automatically makes properties observable with sensible defaults, reducing boilerplate for simple cases.
/**
* Automatically makes object properties observable with sensible defaults
* @param target - Object to make observable
* @param overrides - Override default annotations for specific properties
* @param options - Configuration options
* @returns The target object with automatically detected observable properties
*/
function makeAutoObservable<T extends object>(
target: T,
overrides?: AnnotationsMap<T>,
options?: MakeObservableOptions
): T;Usage Examples:
import { makeAutoObservable } from "mobx";
class Counter {
count = 0;
constructor() {
// Automatically detects:
// - count as observable
// - increment/decrement as actions
// - doubled as computed
makeAutoObservable(this);
}
get doubled() {
return this.count * 2;
}
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
// With overrides
class TodoStore {
todos = [];
private userId = null; // Won't be observable due to private
constructor() {
makeAutoObservable(this, {
userId: false // Explicitly exclude from observability
});
}
}Extends existing objects with new observable properties, useful for adding reactive properties to existing instances.
/**
* Extends an existing object with new observable properties
* @param target - Object to extend
* @param properties - Properties to add
* @param decorators - Annotations for the new properties
* @param options - Configuration options
* @returns The extended object
*/
function extendObservable<A extends object, B extends object>(
target: A,
properties: B,
decorators?: AnnotationsMap<B>,
options?: CreateObservableOptions
): A & B;Usage Examples:
import { extendObservable, observable, computed } from "mobx";
const person = { name: "Alice" };
// Add observable properties
extendObservable(person, {
age: 25,
get info() {
return `${this.name} (${this.age})`;
}
}, {
age: observable,
info: computed
});
console.log(person.info); // "Alice (25)"
person.age = 26;
console.log(person.info); // "Alice (26)"Wrapper for primitive values to make them observable.
interface IObservableValue<T> {
/** Get current value */
get(): T;
/** Set new value */
set(value: T): void;
/** Observe changes to this value */
observe(listener: (change: IValueDidChange<T>) => void): () => void;
/** Intercept changes before they are applied */
intercept(interceptor: IInterceptor<IValueWillChange<T>>): () => void;
}
interface IValueDidChange<T> {
type: "update";
object: IObservableValue<T>;
newValue: T;
oldValue: T;
}Enhanced array with observable capabilities and additional utility methods.
interface IObservableArray<T> extends Array<T> {
/** Replace all items with new array */
replace(newItems: T[]): T[];
/** Clear all items */
clear(): T[];
/** Remove specific value (first occurrence) */
remove(value: T): boolean;
/** Enhanced splice with array parameter */
spliceWithArray(index: number, deleteCount?: number, newItems?: T[]): T[];
/** Convert to plain JavaScript array */
toJSON(): T[];
/** Observe array changes */
observe<T>(listener: (change: IArrayDidChange<T>) => void): () => void;
/** Intercept array changes */
intercept<T>(interceptor: IInterceptor<IArrayWillChange<T>>): () => void;
}
interface IArrayDidChange<T> {
type: "splice";
object: IObservableArray<T>;
index: number;
removed: T[];
added: T[];
removedCount: number;
addedCount: number;
}Observable Map implementation with additional utility methods.
class ObservableMap<K, V> extends Map<K, V> {
constructor(initialData?: IObservableMapInitialValues<K, V>);
/** Convert to plain JavaScript object (string keys only) */
toJSON(): { [key: string]: V };
/** Get all values as array */
values(): V[];
/** Get all keys as array */
keys(): K[];
/** Get all entries as array */
entries(): [K, V][];
/** Merge another object/map into this map */
merge(other: ObservableMap<K, V> | { [key: string]: V }): ObservableMap<K, V>;
/** Replace all entries */
replace(values: IObservableMapInitialValues<K, V>): ObservableMap<K, V>;
/** Observe map changes */
observe(listener: (change: IMapDidChange<K, V>) => void): () => void;
/** Intercept map changes */
intercept(interceptor: IInterceptor<IMapWillChange<K, V>>): () => void;
}
type IObservableMapInitialValues<K, V> =
| IMapEntries<K, V>
| IKeyValueMap<V>
| ObservableMap<K, V>;Observable Set implementation with utility methods.
class ObservableSet<T> extends Set<T> {
constructor(initialData?: IObservableSetInitialValues<T>);
/** Convert to plain JavaScript array */
toJSON(): T[];
/** Replace all values */
replace(other: IObservableSetInitialValues<T>): ObservableSet<T>;
/** Add multiple values */
union(other: IObservableSetInitialValues<T>): ObservableSet<T>;
/** Keep only values that exist in both sets */
intersect(other: IObservableSetInitialValues<T>): ObservableSet<T>;
/** Remove values that exist in other set */
difference(other: IObservableSetInitialValues<T>): ObservableSet<T>;
/** Observe set changes */
observe(listener: (change: ISetDidChange<T>) => void): () => void;
/** Intercept set changes */
intercept(interceptor: IInterceptor<ISetWillChange<T>>): () => void;
}
type IObservableSetInitialValues<T> = IObservableSet<T> | T[];interface CreateObservableOptions {
/** Debug name for the observable */
name?: string;
/** Custom equality comparer */
equals?: IEqualsComparer<any>;
/** Whether to use deep or shallow observability */
deep?: boolean;
/** Default decorator for properties */
defaultDecorator?: Annotation;
/** Whether to use proxy-based observables */
proxy?: boolean;
/** Whether to auto-bind methods */
autoBind?: boolean;
}
interface MakeObservableOptions {
/** Debug name for the observable */
name?: string;
/** Whether to auto-bind methods to the instance */
autoBind?: boolean;
}interface AnnotationsMap<T> {
[K in keyof T]?: Annotation | boolean;
}
interface Annotation {
annotationType_: string;
make_(target: any, property: PropertyKey, descriptor: PropertyDescriptor, source: any): any;
extend_(target: any, property: PropertyKey, descriptor: PropertyDescriptor, proxyTrap: any): any;
}
// Built-in annotations
declare const observable: Annotation;
declare const computed: Annotation;
declare const action: Annotation;
declare const flow: Annotation;
declare const override: Annotation;