如何实现TypeScript文档中的makeWatchedObject函数?
解决
makeWatchedObject未定义的错误并实现TypeScript手册中的示例 TypeScript手册里的这段代码只包含类型定义(declare function仅用于告知TypeScript类型信息,没有实际运行逻辑),直接用Node运行会报ReferenceError,因为JavaScript环境中不存在该函数的实际实现。
以下是完全符合类型要求的可运行实现,通过Proxy拦截属性修改并触发对应回调:
type PropEventSource<Type> = { on<Key extends string & keyof Type>( eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void ): void; }; function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type> { // 存储每个事件对应的回调列表 const callbacks = new Map<string, Array<(value: unknown) => void>>(); // 创建代理对象拦截属性设置操作 const proxy = new Proxy(obj, { set(target, prop, newValue) { // 先更新目标对象的属性值 (target as Record<string, unknown>)[prop as string] = newValue; // 触发对应的XXXChanged事件回调 const eventName = `${prop}Changed`; callbacks.get(eventName)?.forEach(callback => callback(newValue)); return true; } }); // 为代理对象挂载on方法,用于注册事件回调 (proxy as Type & PropEventSource<Type>).on = <Key extends string & keyof Type>( eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void ) => { if (!callbacks.has(eventName)) { callbacks.set(eventName, []); } callbacks.get(eventName)!.push(callback); }; return proxy as Type & PropEventSource<Type>; } // 测试代码 const person = makeWatchedObject({ firstName: "Saoirse", lastName: "Ronan", age: 26 }); person.on("firstNameChanged", newName => { console.log(`new name is ${newName.toUpperCase()}`); }); person.on("ageChanged", newAge => { if (newAge < 0) { console.warn("warning! negative age"); } }); // 修改属性触发回调 person.firstName = "Emily"; // 输出:new name is EMILY person.age = -1; // 输出:warning! negative age
实现核心逻辑:
- 用
Proxy拦截对象的set操作,当属性被修改时自动触发对应XXXChanged事件的回调 - 用
Map存储每个事件对应的回调函数列表,实现多回调注册 - 为代理对象扩展
on方法,完成回调的注册逻辑
将代码保存为.ts文件后,可通过tsc编译为JavaScript再用Node运行,或直接用ts-node执行即可正常运行。
内容的提问来源于stack exchange,提问作者ShouGuouo
相关产品推荐
相关产品推荐

