But imagine that TypeScript in addition to pure functions you can also tag objects as "POD objects" or "JavaScript objects". The POD ("plain old data") objects can't be proxies or have impure getter methods, and only POD objects can be passed to pure functions. The "pure" keyword actually means "pure if all arguments are POD objects" (this is to avoid having to write N purity overloads for an N-ary function).
You want to call a pure method from your impure method, and pass it one of your arguments. Your arguments now need to be declared to be POD objects, which means they are incompatible with the rest of your code base. This has to go all the way up... it's basically "colored functions" except it's colored objects this time, and the colors are completely incompatible (async functions can call sync functions, but impure functions can't call pure functions with impure arguments, and pure functions can't call impure functions at all).
[0] https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgYgewVA...
I'm aware. That doesn't make it impossible to differentiate as Webstorm shows by coloring the bar differently for fooA vs fooB in your example. But yes, it would have to be implemented as part of that pure feature.
It's especially bad to do this if you're going to perform optimizations based on those safety guarantees (thankfully, typescript doesn't do that.) You can say 'don't use the pure keyword then' but the fundamental design of JS means that in practice almost no functions can be pure. The runtime has to identify cases on the fly where pure optimizations are actually valid.
Though now I’m doubting myself because maybe it’s possible to use complex enough assertion functions to really prove that. But even if you don’t, it’s still an incredibly useful language. You’re basically saying, if X is true then the rest of this program should fit together like so.”
You're right that in the end once you pull in outside data you're having to make promises that you may not be able to keep - I just think purity is an especially difficult set of promises to keep, and the existence of proxies and getters in JS (along with how they work) makes purity basically impossible, so it's just a footgun waiting to be used. And TS isn't going to optimize your code using it, so it's not really delivering value either.
Your last argument is confusing: the same applies to everything in typescript. You can also pass in a string to a field that's demanding a number by using "as" so you never have any type guarantees in TS, there is value in it nonetheless.
And the same would surely apply to pure functions (I.e. inpureFunction as PureFunction)()...) It could still be a valuable feature anyway