Static types are great because they make certain classes of bug impossible to write, but they have their limits. There are escape hatches, like casts and Object types, even in statically-typed languages, though fewer of them in languages with more advanced type systems. There are reasons to like PureScript over TypeScript, just as there are reasons to like Haskell over Java. TypeScript doesn’t give you a way to ban side effects, for example, being part of the imperative family of languages that it is. So if you are super into banning side effects you might like a language that does.
The thing to realize is that at the end of the day, all you are doing is reducing bugs, and while your type system (IMO) really can help reduce bugs, it will never catch all bugs. There is still value in a function declaring that its argument is of type User (and not defensively checking it) even if it is theoretically possible, in the presence of a bug, though unlikely, that the argument is not really a User. The function has said what its precondition is, and (assuming you are validating any data that comes over the network or from an untyped source), this precondition will in practice be checked 99% of the time. If a bug happens to line up with a hole in the type system, you’ll just have to debug and fix it.
> Static types are great because they make certain classes of bug impossible to write, but they have their limits. There are escape hatches, like casts and Object types, even in statically-typed languages
Even those don't have to be escape hatches as such, in the same way e.g. List.head doesn't have to be partial, that was an explicit decision.
When casting from rust's Any trait to a concrete type, you get an option. There's no subversion of the type system, there is no runtime error unless you as the developer decide to generate one.
All good points, but I'm having a hard time with this statement:
"There is still value in a function declaring that its argument is of type User (and not defensively checking it) even if it is theoretically possible, in the presence of a bug, though unlikely, that the argument is not really a User."
I'm trying to think of a statically-typed language that would allow such a thing, and I can't, so I assume that you're referring to TypeScript here where you have a world where things are "partially-typed" ?
In TypeScript you could also pass `any` as argument to such function and the compiler would be happy. Of course the noImplicitAny flag helps here, but sometimes you could get `any` from a library with poorly written types as well.
This produces a similar error ("Type 5 is not assignable to type 'string'") when compiled with TS:
var s: string = "Dog";
s = 5;
The difference is that it's a compile-time error, while in PowerShell it's a run-time check. But what's the difference in this case? Either way, it tells you.
The thing to realize is that at the end of the day, all you are doing is reducing bugs, and while your type system (IMO) really can help reduce bugs, it will never catch all bugs. There is still value in a function declaring that its argument is of type User (and not defensively checking it) even if it is theoretically possible, in the presence of a bug, though unlikely, that the argument is not really a User. The function has said what its precondition is, and (assuming you are validating any data that comes over the network or from an untyped source), this precondition will in practice be checked 99% of the time. If a bug happens to line up with a hole in the type system, you’ll just have to debug and fix it.