1

https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

type PropEventSource<Type> = {
    on<Key extends string & keyof Type>
        (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void ): void;
};
 
declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;
 
const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26
});
 
person.on("firstNameChanged", newName => {
                                
(parameter) newName: string
    console.log(`new name is ${newName.toUpperCase()}`);
});
 
person.on("ageChanged", newAge => {
                          
(parameter) newAge: number
    if (newAge < 0) {
        console.warn("warning! negative age");
    }
})

when I run this example using node, an error occurred:

ReferenceError: makeWatchedObject is not defined

I am trying to implement this function, but I failed.
I searched, but no one had the same doubts.
Who can help me?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
ShouGuouo
  • 11
  • 3
  • Some ideas: https://stackoverflow.com/questions/50020982/how-to-subscribe-to-object-changes – kelsny Sep 16 '22 at 15:57
  • What's wrong with your attempt? Did you try anything yet? Can you include your attempt, if you made one? – kelsny Sep 16 '22 at 16:08
  • First of all, remove the `(parameter) name: type` stuff you copied from that page; that was just to illustrate the type inference TypeScript does. Secondly, study up on [`Proxy` objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). – Heretic Monkey Sep 16 '22 at 16:20

1 Answers1

0

Your replies inspired me a lot, I first try to implement it without type

function makeWatchedObject(obj) {
    const cache = new Map()
    const on = (change, callback) => {
        cache.set(change.replace("Changed", ""), callback)
    }
    return new Proxy({
        ...obj,
        on: on
    }, {
        set: (target, p, newValue) => {
            cache.get(p)(newValue)
            return true
        }
    })
}

then i try to add types for it

function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type> {
    const cache = new Map<string | symbol, (newValue: any) => void>()
    const on = (change:string | symbol, callback: (newValue: any) => void) => {
        cache.set(typeof change === "string" ? change.replace("Changed", "") : change, callback)
    }
    return new Proxy<Type & PropEventSource<Type>>({
        ...obj,
        on: on
    }, {
        set: (target: Type, p: string | symbol, newValue: any) => {
            cache.get(p)?.(newValue)
            return true
        }
    })
}

As a backend, the implementation is blunt, but it works. >.<

ShouGuouo
  • 11
  • 3