Skip to content

Instantly share code, notes, and snippets.

@Niakr1s
Created February 1, 2021 09:11
Show Gist options
  • Save Niakr1s/9e4489a54b6f669d8030e93a0b9a5e4e to your computer and use it in GitHub Desktop.
Save Niakr1s/9e4489a54b6f669d8030e93a0b9a5e4e to your computer and use it in GitHub Desktop.
interface Person {
name: string;
surname: string;
}
type StringKeys<T> = string & keyof T;
type KeyChangedCallback<T> = (key: StringKeys<T>, obj: T) => void;
type UnsubscribeFn = () => void;
type KeyChangeObservable<T> = T & { onKeyChanged: (keyName: StringKeys<T>, cb: KeyChangedCallback<T>) => UnsubscribeFn }
function newKeyChangeWatcher<T extends object>(obj: T): KeyChangeObservable<T> {
const callbacks: { [k in StringKeys<T>]?: KeyChangedCallback<T>[] } = {}
const subscribe = (keyName: StringKeys<T>, cb: KeyChangedCallback<T>): UnsubscribeFn => {
callbacks[keyName] ||= [];
callbacks[keyName]!.push(cb);
const unsubscribe = () => {
callbacks[keyName] = callbacks[keyName]!.filter(storedCb => storedCb !== cb);
};
return unsubscribe
}
const proxy = new Proxy(obj, {
set(target, prop, value, _receiver): boolean {
const key = prop as StringKeys<T>;
target[key] = value;
if (prop in callbacks) {
callbacks[key]!.forEach((cb) => {
cb(key, target);
})
}
return true;
},
}) as KeyChangeObservable<T>;
proxy.onKeyChanged = (keyName, cb) => {
return subscribe(keyName, cb);
}
return proxy;
}
let p: Person = {
name: 'Person',
surname: 'Personov',
}
const newOnKeyChangedCallback = (subscriberId: number): KeyChangedCallback<Person> => {
return (key, person) => {
console.log(`Subscriber ${subscriberId}: ${key} -> ${person[key]}`);
};
}
let observableP = newKeyChangeWatcher(p);
const unsubscribe1 = observableP.onKeyChanged("name", newOnKeyChangedCallback(1))
const unsubscribe2 = observableP.onKeyChanged("name", newOnKeyChangedCallback(2))
const unsubscribe3 = observableP.onKeyChanged("surname", newOnKeyChangedCallback(3))
for (let i = 0; i < 10; i++) {
observableP.name = `Person ${i}`;
if (i === 3) unsubscribe1();
if (i === 7) unsubscribe2();
}
for (let i = 0; i < 5; i++) {
observableP.surname = `Personov ${i}`;
if (i === 3) unsubscribe3();
}
console.log(observableP);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment