On some level, virtually all bugs that present inconsistently (i.e., not “every single time I do X, the app does Y”, but “if I do X enough times, sometimes the app does Y”) represent race conditions, meaning you are relying on assumptions that don’t always hold about the order that your code is executing.
So, if you’ve got co-workers, I would ask one of them to review your code for race conditions. Sometimes they’re very hard to spot, especially by the eyes that made the mistake in the first place.
If you don’t have coworkers, and are willing to show the entire app repository (this sort of problem is notoriously ill-suited to posting individual snippets out of context, because one needs to see the entire code flow to spot many of the problems), that’s another option, and maybe somebody here will help with this.
If neither of those options work for you, and you want to try to do this yourself, here’s a mini-checklist of rocks you can turn over to see if anything crawls out:
- get rid of any use of
async
and await
- give explicit, proper (not
any
) types to all parameters and return values of all methods
- add strict options to
tsconfig.json
, like:
"compilerOptions": {
...
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictPropertyInitialization": true
},
{
"angularCompilerOptions": {
...
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
- pay strict attention to any build-time complaints triggered by adding these compiler options, because failing to initialize something can often be covered up by code that “generally” executes fast enough
- if you ever call a function that returns a future (
Promise
or Observable
) (including the ones you write yourself, and knowing for certain which ones these are is a key part of why the first two steps on this list are there), think about how you are dealing with it. Generally, you would want to also be returning a future from the calling function that’s dependent on the one you got. If you’re not, think hard about whether people who are calling this function care about when it does its work. If they do, and you’re not returning a future, you’re toast. There’s no way that the caller can know when that work has completed.
- the advice in the previous bit very much applies to calls to native plugins, which all return futures of some sort.
Good luck.