SharedMap provides a distributed key-value data structure with a JavaScript Map-compatible API. It automatically synchronizes changes across multiple clients using last-write-wins conflict resolution.
Creates a new SharedMap instance for collaborative key-value storage.
/**
* Creates a new SharedMap instance
* @param runtime - Fluid data store runtime
* @param id - Optional unique identifier for the map
* @returns SharedMap instance
*/
const SharedMap: ISharedObjectKind<ISharedMap>;
interface ISharedObjectKind<T> {
create(runtime: IFluidDataStoreRuntime, id?: string): T;
getFactory(): IChannelFactory;
}Usage Example:
import { SharedMap } from "@fluidframework/map";
// Create a new shared map
const userPreferences = SharedMap.create(runtime, "user-prefs");
const gameState = SharedMap.create(runtime); // Auto-generated IDRetrieves values from the SharedMap by key.
/**
* Retrieves the given key from the map if it exists
* @param key - Key to retrieve from
* @returns The stored value, or undefined if the key is not set
*/
get<T = any>(key: string): T | undefined;Usage Examples:
// Basic value retrieval
const userName = myMap.get("user-name");
const config = myMap.get("app-config");
// Type-safe retrieval with generics
const score = myMap.get<number>("player-score");
const settings = myMap.get<UserSettings>("user-settings");
// Check if value exists
if (myMap.has("feature-flag")) {
const isEnabled = myMap.get<boolean>("feature-flag");
}Sets key-value pairs in the SharedMap, which automatically synchronizes to other clients.
/**
* Sets the value stored at key to the provided value
* @param key - Key to set
* @param value - Value to set (must be JSON-serializable or a handle)
* @returns The ISharedMap itself for chaining
*/
set<T = unknown>(key: string, value: T): this;Usage Examples:
// Set primitive values
myMap.set("user-count", 42);
myMap.set("app-name", "My Collaborative App");
myMap.set("is-active", true);
// Set complex objects (must be JSON-serializable)
myMap.set("user-profile", {
name: "Alice",
email: "alice@example.com",
preferences: { theme: "dark", lang: "en" }
});
// Set arrays
myMap.set("recent-actions", ["login", "view-dashboard", "edit-profile"]);
// Chaining operations
myMap
.set("initialized", true)
.set("last-update", new Date().toISOString())
.set("version", "1.0.0");Checks whether a key exists in the SharedMap.
/**
* Returns true if the specified key exists, false otherwise
* @param key - Key to check for
* @returns Boolean indicating key existence
*/
has(key: string): boolean;Usage Examples:
// Check before getting
if (myMap.has("user-settings")) {
const settings = myMap.get("user-settings");
// Process settings...
}
// Conditional logic based on key existence
const theme = myMap.has("theme") ? myMap.get("theme") : "light";Removes key-value pairs from the SharedMap.
/**
* Removes the specified key and its value from the map
* @param key - Key to delete
* @returns True if the key existed and was deleted, false if it didn't exist
*/
delete(key: string): boolean;Usage Examples:
// Delete a specific key
const wasDeleted = myMap.delete("temporary-data");
if (wasDeleted) {
console.log("Temporary data was removed");
}
// Clean up expired data
if (myMap.has("session-token")) {
myMap.delete("session-token");
}Removes all key-value pairs from the SharedMap.
/**
* Removes all key-value pairs from the map
*/
clear(): void;Usage Example:
// Reset the entire map
myMap.clear();
console.log(myMap.size); // 0Returns the number of key-value pairs in the SharedMap.
/**
* Returns the number of key-value pairs in the map
*/
readonly size: number;Usage Examples:
console.log(`Map contains ${myMap.size} items`);
// Check if map is empty
if (myMap.size === 0) {
console.log("Map is empty");
}Iterates over all keys in the SharedMap.
/**
* Returns an iterator over the keys in the map
* @returns Iterator for map keys
*/
keys(): IterableIterator<string>;Usage Examples:
// Iterate over all keys
for (const key of myMap.keys()) {
console.log(`Key: ${key}, Value: ${myMap.get(key)}`);
}
// Convert to array
const allKeys = Array.from(myMap.keys());
console.log("All keys:", allKeys);Iterates over all values in the SharedMap.
/**
* Returns an iterator over the values in the map
* @returns Iterator for map values
*/
values(): IterableIterator<any>;Usage Examples:
// Iterate over all values
for (const value of myMap.values()) {
console.log("Value:", value);
}
// Process all values
const allValues = Array.from(myMap.values());
const processedValues = allValues.filter(v => v !== null);Iterates over all key-value pairs in the SharedMap.
/**
* Returns an iterator over key-value pairs in the map
* @returns Iterator for [key, value] pairs
*/
entries(): IterableIterator<[string, any]>;
/**
* Default iterator - same as entries()
*/
[Symbol.iterator](): IterableIterator<[string, any]>;Usage Examples:
// Iterate over entries using for...of
for (const [key, value] of myMap) {
console.log(`${key}: ${value}`);
}
// Explicit entries iteration
for (const [key, value] of myMap.entries()) {
console.log(`Entry - ${key}: ${JSON.stringify(value)}`);
}
// Convert to array of entries
const entries = Array.from(myMap.entries());
console.log("All entries:", entries);Executes a callback function for each key-value pair in the SharedMap.
/**
* Executes a provided function once for each key-value pair
* @param callbackfn - Function to execute for each entry
* @param thisArg - Optional value to use as 'this' when executing callback
*/
forEach(callbackfn: (value: any, key: string, map: Map<string, any>) => void, thisArg?: any): void;Usage Examples:
// Basic forEach usage
myMap.forEach((value, key) => {
console.log(`Processing ${key}: ${value}`);
});
// With index tracking
let index = 0;
myMap.forEach((value, key) => {
console.log(`Item ${index++}: ${key} = ${value}`);
});
// Using thisArg
const processor = {
prefix: "Data:",
process(value: any, key: string) {
console.log(`${this.prefix} ${key} = ${value}`);
}
};
myMap.forEach(function(value, key) {
this.process(value, key);
}, processor);SharedMap emits events when data changes, enabling reactive programming patterns.
interface ISharedMapEvents extends ISharedObjectEvents {
/**
* Emitted when a key is set or deleted
* @param changed - Information about the key that changed
* @param local - Whether the change originated from this client
*/
(event: "valueChanged", listener: (changed: IValueChanged, local: boolean, target: IEventThisPlaceHolder) => void): any;
/**
* Emitted when the map is cleared
* @param local - Whether the clear originated from this client
*/
(event: "clear", listener: (local: boolean, target: IEventThisPlaceHolder) => void): any;
}
interface IValueChanged {
readonly key: string;
readonly previousValue: any;
}Usage Examples:
// Listen for value changes
myMap.on("valueChanged", (changed, local) => {
console.log(`Key "${changed.key}" changed from:`, changed.previousValue);
console.log(`New value:`, myMap.get(changed.key));
console.log(`Change was ${local ? "local" : "from another client"}`);
});
// Listen for map clear events
myMap.on("clear", (local) => {
console.log(`Map was cleared ${local ? "locally" : "by another client"}`);
});
// One-time event listeners
myMap.once("valueChanged", (changed, local) => {
console.log("First change detected:", changed.key);
});
// Remove event listeners
const valueChangeHandler = (changed, local) => {
// Handle change...
};
myMap.on("valueChanged", valueChangeHandler);
// Later...
myMap.off("valueChanged", valueChangeHandler);SharedMap values must be:
Valid values:
myMap.set("string", "hello");
myMap.set("number", 42);
myMap.set("boolean", true);
myMap.set("null", null);
myMap.set("object", { name: "Alice", age: 30 });
myMap.set("array", [1, 2, 3]);
myMap.set("date-string", new Date().toISOString());Invalid values:
// These will not synchronize properly
myMap.set("function", () => console.log("hello")); // Functions
myMap.set("date-object", new Date()); // Date objects (use toISOString())
myMap.set("regex", /pattern/); // Regular expressions
myMap.set("symbol", Symbol("unique")); // SymbolsSharedMap uses last-write-wins conflict resolution: