mobx-keystone-mindreframer
Version:
A MobX powered state management solution based on data trees with first class support for Typescript, snapshots, patches and much more
115 lines (97 loc) • 2.88 kB
text/typescript
import { entries, get, has, keys, remove, set, values } from "mobx"
import { modelAction } from "../action/modelAction"
import { Model } from "../model/Model"
import { model } from "../modelShared/modelDecorator"
import { typesRecord } from "../typeChecking/record"
import { tProp } from "../typeChecking/tProp"
import { typesUnchecked } from "../typeChecking/unchecked"
/**
* A map that is backed by an object-like map.
* Use `objectMap` to create it.
*/
export class ObjectMap<V>
extends Model({
items: tProp(typesRecord(typesUnchecked<any>()), () => ({})), // will be properly checked by types.objectMap(subType)
})
implements Map<string, V> {
clear(): void {
const items = this.items
const keys = Object.keys(items)
const len = keys.length
for (let i = 0; i < len; i++) {
const k = keys[i]
remove(items, k)
}
}
delete(key: string): boolean {
const hasKey = this.has(key)
if (hasKey) {
remove(this.items, key)
return true
} else {
return false
}
}
forEach(callbackfn: (value: V, key: string, map: Map<string, V>) => void, thisArg?: any): void {
// we cannot use the map implementation since we need to pass this as map
const items = this.items
const keys = Object.keys(items)
const len = keys.length
for (let i = 0; i < len; i++) {
const k = keys[i]
callbackfn.call(thisArg, items[k], k, this)
}
}
get(key: string): V | undefined {
return get(this.items, key)
}
has(key: string): boolean {
return has(this.items, key)
}
set(key: string, value: V): this {
set(this.items, key, value)
return this
}
get size(): number {
return keys(this.items).length
}
keys(): IterableIterator<string> {
// TODO: should use an actual iterator
return keys(this.items)[Symbol.iterator]() as IterableIterator<string>
}
values(): IterableIterator<V> {
// TODO: should use an actual iterator
return values(this.items)[Symbol.iterator]()
}
entries(): IterableIterator<[string, V]> {
// TODO: should use an actual iterator
return entries(this.items)[Symbol.iterator]()
}
[Symbol.iterator](): IterableIterator<[string, V]> {
return this.entries()
}
get [Symbol.toStringTag](): string {
return "ObjectMap"
}
}
/**
* Creates a new ObjectMap model instance.
*
* @typeparam V Value type.
* @param [entries] Optional initial values.
*/
export function objectMap<V>(entries?: ReadonlyArray<readonly [string, V]> | null): ObjectMap<V> {
const initialObj: { [k: string]: V } = {}
if (entries) {
let len = entries.length
for (let i = 0; i < len; i++) {
const entry = entries[i]
initialObj[entry[0]] = entry[1]
}
}
return new ObjectMap({ items: initialObj })
}