This is exactly my experience. I've also found that Python's type annotations for even basic stuff like are way clunkier to write.
For example an optional requires a typing.Optional import or a an ugly "| None" instead of a question mark like TS has. And good luck trying to annotate some complex / nested json, you'll need a bazillion intermediary classes.
There's a subtle difference between TS' question mark and union. The question mark means "this argument is optional", which can be different than "this argument can be undefined".
The following code is valid:
function foo1(value?: number) {}
foo1()
But the following code will raise a type error:
function foo2(value: number | undefined) {}
foo2()
In practice, that rarely becomes problematic. But it's good to know the difference
This conflation of "optional" and "undefined-able" is more obvious in interfaces. This is why TypeScript added the `exactOptionalPropertyTypes` option:
For example an optional requires a typing.Optional import or a an ugly "| None" instead of a question mark like TS has. And good luck trying to annotate some complex / nested json, you'll need a bazillion intermediary classes.