Hacker News new | past | comments | ask | show | jobs | submit login
Problems with TypeScript in 2020 (executeprogram.com)
46 points by execute_program on April 15, 2020 | hide | past | favorite | 18 comments



TL;DR: “TypeScript sucks because JavaScript sucks - namely buggy development file-watchers and npm - and some @types packages for more obscure npm packages are inadequate.”

If that’s the worst people can levy at TypeScript I’d say it’s a pretty danged good language.

What I hate about TypeScript is that it’s made me feel that all other programming languages’ type systems are inadequate in comparison (union and intersection types, Utility types, immutable and read-only views of existing objects, type guards for duck-typing, etc).


It's a fixable problem. The attraction of Typescript was that all javascript is valid typescript. Great feature in the past years where people were migrating from one to the other. But now that most projects start out on typescript (honestly, if you are not you are doing it wrong) and never write a single line of Javascript, it's becoming an anti feature. The whole point of typescript is that we want to get away from that madness rather than stay close to it.

It already has a strict mode; it's time for an even stricter mode that simply cuts loose from javascript and flat out removes access to all the little compromises with strong typing that exist only because of javascript. It's a compilation target and with WASM emerging, even that is not a long term certainty.

IMHO the difference between e.g. Kotlin and Typescript is becoming smaller and smaller. I do both. There's been a cross over of lots of nice language features from Kotlin and other languages to Typescript. But at this point, Kotlin is a still a lot cleaner/safer than Typescript even though both can transpile to javascript and it also has a bit nicer ergonomics in some areas. E.g. data classes, property and interface delegation, co-coutines, etc. are all things that would be highly useful in Typescript as well. Android developers seem to love these features. And as Kotlin transpiles to javascript, there's no question about whether or not that can be done because it's already been done.


"Even stricter mode" means interposing more friction. If JS is reduced to a "compilation target" for a language that models some lowest-common-demoninator browser, and requires hoop-jumping to break out of that model, then browsers are forever unable to evolve.


You're describing the past 20 years. Time to move on from that and stop treating this weird convoluted mess as if it's the only way to do things. JS as a compilation target will probably morph into deprecating it in favor of WASM.

In any case, most frontend projects have been using transpilers for quite some time now to deal with compatibility issues. It's browser JS is increasingly used as a compilation target. The exception is smallish websites where people don't care about older browsers or using new js features not yet shipped to browsers. Those exist, but it's becoming a minority.

For the rest of us, browser JS is something ugly and minified that webpack spits out and that you probably rarely even look at.


As a relatively new programmer, I’m kinda of baffled it took up to now to have these features in mainstream programming languages, but I certainly lack a huge amount of historical context.


To some extent a lot of these ideas are still "new", comparatively, to type systems.

It's also easy to argue that Typescript (and Flow, not to ignore its contributions to the space) happened upon exactly the right sort of evolutionary conditions to both need a lot of the complicated features and present them in such a way that they appealed to a "mainstream" audience: a very dynamic base language with a giant corpus of highly varied real world usage, and a growing need for practical "taming" for large real world applications by large corporations (with vested programming language interests).

It's a credit to Typescript (and to Flow as well) that a lot of the complexity in its type system, often designed as best as it could to handle describing the complexity of real world Javascript usage, seems after the fact as "perfectly natural" enough that now in retrospect people start to wonder why more languages don't adopt the same ideas. Sometimes the simple answer is "because they weren't forced to in order to scratch a present need". As people have access to the tools it becomes easier to see "oh, this complex thing that solves this need over here becomes a useful thing to better these nice-to-haves over there".


Throughout the 1990s and early-2000s when Object-oriented programming and its spin-off: Component-oriented programming, were popular, there wasn't any interest in functional programming nor concepts like immutability (which, at face-value, flies in the face of OOP (until you gain a deeper understanding and agree it's a very good thing)). Haskell itself didn't attract much attention until the mid-2000s.


Mainly that there are many ways to express things, and inertia means reasonably effective solutions within existing type systems limits the push for more expressivity. Programming languages are slowly converging on features (e.g. lambdas) but it's a slow convergence. I think programming languages over time will get more complex, but more concepts will be portable


if types is what you want, typescript is a toy compared to something like purescript. Interop is another thing. That JS interop is typescript's killer feature in my option.

Typescript strikes a great compromise between enough flexibility to get out of your way + type checking to keep you from hanging yourself. Its also easy as hell to learn. I can hire a js engineer and upgrade them into a typescript one in a day or two.


I doubts purescript or any other hindley milner type system has proper union (not sum) types. As far as I see one of the advantages of typescript is that it is fine with some degree of unsoundness if it mean better ergonomics.


Sum types and newtypes behind smart constructors are better ways of accomplishing what you'd usually use union types for, I think?


Strongly disagree. There are two scenario in my mind where union types have distinct advantage

1) they allow for "anonymous types", suppose a function can receive a List or a Dictionary, you could define a type List_or_Dict or (Either List Dict) or Result<List,Dict>, but all of them require you to either have the same sum type at the call site or declare explicitly whether you have a List or a Dict by choosing a type constructor at call site, thus breaking the polymorphism of the union List|Dict (where `|` means union). Another similar example would be with a variable x of type List|Dict and a function f that again accept a String|List|Dict, with union types the call f(x) is perfectly valid.

2) the second advantage is that now you can treat constructors as their own type and define type with arbitrary combinations of them. For example you could define three constructor Ok: a -> Ok a, Err: a -> Err a, None: None and then have an option type defined as Ok a | None and a result type defined as Ok a | Err b. in this situation there would be no need to convert success type of an option into success type of a result as they are already the same type.

This makes type inference extremely more complex but ocaml shows that it can be done (this actually negates my initial point)


I think number one can be handled with type classes. Usually if you want to pass in radically different structures there's some common underlying structure.


type classes sort of solve the same problem and in both rust and haskell they can sort of emulate union types (I have no idea about the details, I am not an expert of subtyping).

Still the usability feature of being able to quickly create arbitrary union types is undeniable (Julia uses something similar as a main source of polymorphism and personally I think it is amazing)


All those features are present in other languages too, the premise that no other useful or mainstream languages don’t is false. For example Swift has all of those features.


Swift doesn't have first-class intersection-types or discriminated-unions (it has a variation on Java's enum types, which are close, but not exactly the same, e.g. you can't use a custom type defined elsewhere as a discriminated-union type: you have to use an enum case as the containing type - this is not a huge problem, just an ergonomic frustration).

Additionally, I don't believe Swift supports true structural typing (i.e. Duck-typing). If you have a method that accepts a protocol-implementing object, that object has to explicitly implement that protocol, it can't be inferred by the compiler.

In a similar vein, C# also supports intersection type (but only intersection-of-interfaces in type-parameterized generic methods) or structural-typing (again, via generics with explicit implementation). Please correct me if I'm wrong, but to my knowledge Swift doesn't support call-site structural typing nor true intersection types (i.e. intersection of non-interface types).


Swift is missing a lot of features, and that's why you can see a lot of type operators and type-level programming in some TypeScript code. For example, there is no Higher-Kind type support in TypeScript, but with some primitives from TypeScript, it's not hard to hack it out yourself. I doubt it's viable in Swift.

Among those mainstream languages, not many of them having such an advanced type system, with very few exceptions like Scala - even with GADT, dependent types ahead. It's light years ahead of its peers.

But I believe there are still some abstractions can be expressed in TypeScript but not Scala because the gradually/dynamically typed languages start from the opposite side from the spectrum.


My path to happiness is to only use TypeScript in projects that are built from the ground up to use it, otherwise I rather stay with JavaScript than dealing with library integration issues.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: