[Typescript] Builder pattern - 06 Exercise
type TMethodListener<T> = (copyFn: T, ...args: any[]) => void;
type TBuildInfo<TOverriden> = {
mutationList: TOverriden;
error?: string;
};
/**
* @description
*
* Overriden class helps to overriden object.
*
* Prevent override the methods which already been overriden;
* This is not applied to props
*
* .method(methodName, callback: (originalFunction: Function, ...args: any[]) => void)
* .prop(propName, callback: (prevVal) => newVal): overriden the prop with new value]
* .build(callback?: (overridenList) => void): get final overriden object back,
* callback function get all the overriden props and methods array
*/
class Overriden<TMap extends object = {}, TOverriden extends string[] = []> {
#map: TMap;
#overriden = [] as any as TOverriden;
#done = false;
#error?: string;
constructor(obj: TMap) {
this.#map = obj;
}
build(callback?: (info: TBuildInfo<TOverriden>) => void) {
this.#checkDone();
this.#done = true;
if (callback && typeof callback === "function") {
callback({
mutationList: this.#overriden,
error: this.#error,
});
}
return this.#map;
}
prop<TPropName extends keyof TMap & string, RT>(
propName: TPropName extends TOverriden[number] ? never : TPropName,
listener: (prevVal: TMap[TPropName]) => RT
): Overriden<Record<TPropName, RT> & TMap, [...TOverriden, TPropName]> {
this.#checkDone();
(this.#map as any)[propName] = listener(this.#map[propName]);
this.#overriden.push(propName);
return this as any;
}
method<TMethodName extends keyof TMap & string>(
methodName: TMethodName extends TOverriden[number] ? never : TMethodName,
listener: TMethodListener<TMap[TMethodName]>
): TMethodName extends TOverriden[number]
? Overriden<TMap, TOverriden>
: Overriden<
Record<TMethodName, TMethodListener<TMap[TMethodName]>> & TMap,
[...TOverriden, TMethodName]
> {
this.#checkDone();
if (typeof this.#map[methodName] !== "function") {
this.#error = `${methodName} not a function`;
throw new Error(this.#error);
}
if (this.#overriden.includes(methodName)) {
this.#error = `${methodName} got overriden already`;
console.warn(this.#error);
return this as any;
}
const copyFn = this.#map[methodName];
(this.#map as any)[methodName] = (...args: any[]) => {
listener.call(this.#map, copyFn, ...args);
};
this.#overriden.push(methodName);
return this as any;
}
#checkDone(): asserts this is this & { error: undefined } {
if (this.#done) {
this.#error =
"There is already another overriden process for the same object";
throw new Error(this.#error);
}
}
}
const win = {
close() {
console.log("close is called");
},
open(...args: any[]) {
console.log("open is called", ...args);
return args[0];
},
alert() {
console.log("alert is called");
},
isObj: true,
type: "window",
info: {
name: "name",
age: 12,
},
};
const overridenWin = new Overriden(win);
const chain = overridenWin
.prop("info", (prevInfo) => {
return { ...prevInfo, address: "new address" };
})
.method("open", (copyFn, ...args) => {
copyFn(...args);
});
// do something here
//
//
const res = chain.method("close", () => {}).build(console.log);
res.info.address;
res.open();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2022-03-11 [React] Animate SVG Paths with Framer Motion
2021-03-11 [AWS Amplify] Deploy Your React Application to AWS Using the Amplify CLI
2021-03-11 [AWS Amplify] Store Data in Amazon S3 with React + Amplify
2021-03-11 [AWS Amplify] Create & Interact with an AWS AppSync GraphQL API with AWS Amplify
2020-03-11 [React] When to useReducer instead of useState
2020-03-11 [Web component] Using Custom Events as a web component API
2019-03-11 [Algorithm] Tower Hopper Problem