I'm going to make my own minimal reproducible example so if you need to tweak it to apply to your use case, hopefully you can. Imagine I have this Foo class that takes a message and concats dates or times or something onto it:
class Foo {
message: string;
constructor(message: string) {
this.message = message;
}
concatDate() {
this.message += " @ " + new Date().toLocaleTimeString();
}
}
let f = new Foo("hello there");
console.log(f.message); // "hello there"
f.concatDate();
console.log(f.message); // "hello there @ 12:56:10 PM"
await new Promise(resolve => setTimeout(resolve, 2000));
f.concatDate();
console.log(f.message); // "hello there @ 12:56:10 PM @ 12:56:12 PM"
Oops, every time I call concatDate() it adds to the end of message. How can I fix it? Well, one idea is that you can try to look at message and strip off any date string if one is there. Like this:
class BadFixFoo {
message: string;
constructor(message: string) {
this.message = message;
}
concatDate() {
this.message = this.message.replace(/ @[^@]*$/, "") +
" @ " + new Date().toLocaleTimeString();
}
}
It kind of works:
f = new BadFixFoo("hello there");
console.log(f.message); // "hello there"
f.concatDate();
console.log(f.message); // "hello there @ 12:56:12 PM"
await new Promise(resolve => setTimeout(resolve, 2000));
f.concatDate();
console.log(f.message); // "hello there @ 12:56:14 PM"
Until it doesn't work:
f = new BadFixFoo("what if I use an @-sign in the message");
console.log(f.message); // "what if I use an @-sign in the message"
f.concatDate();
console.log(f.message); // "what if I use an @ 12:56:14 PM"
await new Promise(resolve => setTimeout(resolve, 2000));
f.concatDate();
console.log(f.message); // "what if I use an @ 12:56:16 PM"
See, the method I used to strip off the date just looked for the last @ sign (after a space) in the message and removed it and everything after it. But if the original message has an @ sign in it, then the stripping will mess it up. Oops. Maybe we can write an even more clever way of identifying a date string, but if the user can truly write anything for the original message, there's nothing we can do to stop them from writing an actual date string. Do we want to strip that off?
If not, you need to refactor so that you're not trying to forensically determine what the original message was. Instead, store it:
class GoodFoo {
originalMessage: string;
message: string;
constructor(message: string) {
this.originalMessage = message;
this.message = message;
}
concatDate() {
this.message = this.originalMessage + " @ " + new Date().toLocaleTimeString();
}
}
This means that concatDate() never tries to modify the current message. Instead, it copies the originalMessage and appends to that:
f = new GoodFoo("what if I use an @-sign in the message");
console.log(f.message); // "what if I use an @-sign in the message"
f.concatDate();
console.log(f.message); // "what if I use an @-sign in the message @ 12:56:16 PM"
await new Promise(resolve => setTimeout(resolve, 2000));
f.concatDate();
console.log(f.message); // "what if I use an @-sign in the mssage @ 12:56:18 PM"
Playground link to code