Types are invaluable when refactoring your code. I have found Typescript to be invaluable when doing exploratory programming as it allows me to refactor heavily as I learn more about the structure of the problem. The compiler points all the affected code sites and I have reasonable confidence in the correctness of the code after the refactor.
Most static type systems really suck and I can fully understand why dynamic-coders don't like them.
It often feels like they are holding you back more than they help.
I also got such a moment with TypeScript.
const a = A()
a.b = new SubtypeOfB()
a.b.attributeOfSubtypeOfB = 123 //error
Because a.b is type B and not SubtypeOfB and so doesn't have the attribute of SubtypeOfB, but a.b gets its typing from A, which can't be changed on the fly later.
The solution was:
const a = A()
const b = new SubtypeOfB()
b.attributeOfSubtypeOfB = 123 //here TS thinks it is SubtypeOfB
a.b = b //now TS thinks it's B
Which felt like "Why do I have to restructure my code with extra variables when I clearly know that this object HAS that attribute?!"
And Java was full of those problems. Numerous different definitions of the same thing that aren't compatible with each other. Hell, some languages even have different string types.
But yeah, TypeScript is generally chill about most things and the hints it gives me were often right and helped to find the right methods without consulting any docs, which is a huge win, even without the refactoring stuff.
You can also use 'type assertions' to minimise restructuring, eg, the following is the same number of lines as your first example (and compiles to identical code):
const a = A()
a.b = new SubtypeOfB()
(<SubtypeOfB> a.b).attributeOfSubtypeOfB = 123 //works