What are the downsides of gradual typing on a codebase? I've never worked with it, but watched some talks on it and it really sounds promising. I understand the downsides for compiler complexity and for performance, but not on the codebase itself.
- Worse type error messages, as the type system has to be more complicated to handle the sorts of patterns that are common in untyped code.
- You can still get type errors at runtime in your typed code, if it interacts with untyped code, because it isn't feasible to validate all types on the boundary. You're only guaranteed no runtime type errors if all of your code is typed.
- The migration path from untyped to typed isn't always easy. Depending on how your code is organized, it's possible to have correct untyped code such that there do not exist type annotations you could add to it that would make it type check.
For one thing: because as soon as some piece of data leaves the typed world, all of your guarantees about its integrity go away. This is, in some sense, even worse than a situation with no types at all - in that case, you have no guarantees, which is better than having misleading ones!
If types are to data flow what structured programming is to control flow, it's a bit like being able to call into unsafe functions that can corrupt your stack. You could waste hours trying to trace the flow of execution and being completely stumped by your code's behaviour, looking at stack traces that make no sense...
Furthering that analogy, like how a structured programming language restricts control flow to specific structures as compared to free-form branches and jumps, certain interfaces and patterns that you can get away with in a dynamic context can't be expressed (or expressed cleanly) in a statically typed language. Just as your average Java programmer doesn't usually feel constricted by the inability to write Duff's Device in their language of choice, once you get good at TypeScript you rarely feel inclined to construct dynamic interfaces, but JS developers...a world where static typing isn't universally enforced, especially if you're working with a bunch of JS devs who don't fully embrace static typing, encourages the construction of difficult-to-type APIs. This then feeds back into the first issue: reasoning about type integrity when using these APIs becomes painfully difficult.
It's not that the general idea of "gradual typing" is bad, but that strong types become a leaky abstraction in practice. If you have to constantly fight against the weakly typed nature of the underlying language, that defeats the point.
> The problem is not as simple as taking the ECMAScript grammar and augmenting it with type annotations. There's a reason that Microsoft (TypeScript, Safe TypeScript), Google (AtScript, SoundScript), and Facebook (Flow) have all collectively attempted this problem and came up short.
Types are ultimately a contract. If your code was not originally designed with these contracts in mind and then you introduce a system that actually promotes ad hoc interfaces (TypeScript or any structurally typed system) then what you get is a mess. You're constantly Pick or Omit-ting everywhere. But worse, you absolutely have to use "any" or "ts-ignore" during the process. You can't avoid it. But one single "any" has the effect of stripping all code of type annotations, making the entire process a giant waste of time.
To compound matters, none of the TypeScript devs I've worked with have any experience with type systems. They don't think in terms of interfaces. They are still ball-of-mud developers. They did not come from Java or C/C++ or even Haskell. They came from Python or Ruby.
I'd also caution people about using third party types (i.e. DefinitelyTyped). These are often not correct because the underlying library is not in TS and does not have type information. You will pull your hair out when the library does not match the type definitions. These third party definitions can introduce bugs into your code. They can falsely claim that some field exists on an object which, in fact, does not. Your IDE will happily autocomplete to the invalid field, TS will happily compile it, and your JS run-time will unhappily crash.
Done badly you can end up doing a lot of admin to make the types work without actually getting the benefit of that type safety. Done well you can get the benefits of type safety where it really counts and avoid the overhead where it doesn’t.
> What are the downsides of gradual typing on a codebase?
Typing complex business domains and interactions is hard. Most developers don’t have a lot of experience with it or the time to do it properly as they produce features. It doesn’t help that many developers start their career with untyped languages and transition into typed languages without learning it properly.
Typescript is a great example because a lot of frontend developers may have only ever worked in JavaScript and have absolutely no foundation to build on but trial and error on your companies production codebase.
It's definitely not that the developers are inexperienced with types. You're sort of making a "white man's burden" argument. Very few web developers are just writing javascript at work.
It's simply that you can't paint over a weakly typed language with strong types without causing all kinds of crazy edge cases. They're fundamentally different paradigms.