Last active
September 8, 2022 13:33
-
-
Save doronguttman/a8a98632066e3dea4af73c16aa60754c to your computer and use it in GitHub Desktop.
Observable map/set (TypeScript)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Observer } from "./vue-helper"; | |
class MapObserver extends Observer { | |
constructor(value: unknown, shallow?: boolean, mock?: boolean) { | |
super(value, shallow, mock); | |
if (!shallow && value instanceof Map) { | |
this.observeArray(value); | |
} | |
} | |
public override observeArray(value: unknown): void { | |
// does not support nested Maps | |
super.observeArray(value instanceof Map ? Array.from(value.values()) : value); | |
} | |
} | |
export class ObservableMap<K, V> extends Map<K, V> { | |
_length = super.size; | |
_notify(method: string) { | |
this._length = super.size; | |
this.__ob__?.dep?.notify({ | |
type: "map mutation", | |
target: this, | |
key: method | |
}); | |
} | |
private readonly __ob__: MapObserver; | |
public constructor(entries?: readonly (readonly [K, V])[] | null) { | |
super(entries); | |
this.__ob__ ??= new MapObserver(this); | |
} | |
public get length() { | |
return this._length; | |
} | |
public override get size() { | |
return this._length; | |
} | |
public override clear() { | |
super.clear(); | |
this._notify("clear"); | |
} | |
public override delete(key: K) { | |
const deleted = super.delete(key); | |
this._notify("delete"); | |
return deleted; | |
} | |
public override set(key: K, value: V) { | |
super.set(key, value); | |
Array.isArray(value) && this.__ob__?.observeArray(value); | |
this._notify("set"); | |
return this; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Observer } from "./vue-helper"; | |
class SetObserver extends Observer { | |
constructor(value: unknown, shallow?: boolean, mock?: boolean) { | |
super(value, shallow, mock); | |
if (!shallow && value instanceof Set) { | |
this.observeArray(value); | |
} | |
} | |
public override observeArray(value: unknown): void { | |
// does not support nested Sets/Maps | |
super.observeArray(value instanceof Set ? Array.from(value.values()) : value); | |
} | |
} | |
export class ObservableSet<T> extends Set<T> { | |
_length = super.size; | |
_notify(method: string) { | |
this._length = super.size; | |
this.__ob__?.dep?.notify({ | |
type: "map mutation", | |
target: this, | |
key: method | |
}); | |
} | |
private readonly __ob__: SetObserver; | |
public constructor(values?: readonly T[] | null | undefined); | |
public constructor(iterable?: Iterable<T> | null | undefined) { | |
super(iterable); | |
this.__ob__ ??= new SetObserver(this); | |
} | |
public get length() { | |
return this._length; | |
} | |
public override get size() { | |
return this._length; | |
} | |
public override clear() { | |
super.clear(); | |
this._notify("clear"); | |
} | |
public override add(value: T): this { | |
super.add(value); | |
this._notify("add"); | |
return this; | |
} | |
public override delete(value: T): boolean { | |
const result = super.delete(value); | |
this._notify("delete"); | |
return result; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vue from "vue"; | |
interface IDep { | |
notify(options: { | |
type: string; | |
target: unknown; | |
key: string; | |
}): void; | |
} | |
interface IObserver { | |
new(value: unknown, shallow?: boolean, mock?: boolean): IObserver; | |
observeArray(value: unknown): void; | |
dep: IDep; | |
} | |
export const Observer = Object.getPrototypeOf((Vue.observable({}) as any)["__ob__"]).constructor as new (value: unknown, shallow?: boolean, mock?: boolean) => IObserver; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment