DEV Community

Dmitry Amelchenko
Dmitry Amelchenko

Posted on

TypeScript -- why not?

I just recently watched https://www.udemy.com/course/typescript-for-javascript-developers ,

While watching it, I could not help but to keep thinking that something is wrong with me...

Googling for "typescript is horrible" revealed a lot of links where people passionately bash TypeScript -- what a relief, it's not me after all. Apparently, there is a lot of controversy around TypeScript.

Watching this Udemy class finally convinced me -- TypeScript really does not solve any issues, it just makes things even more complicated.

In discussions with peer software engineers it always comes up, that, in order to be proficient with more advanced JS concepts, you need to learn the basics first -- to appreciate JS as a language, you have to understand the "weird" prototype inheritance model, you must master the "bind" keyword (ironically, most of JS developers lack these essentials), you need to know and understand ways to define classes with functions, you need to learn and understand functional concepts of JS, you do need to know what ES6/7 brings on the table and why is that an improvement over ES5.

In my career I come across two kinds of software engineers. First will learn few basic programming constructs and start to use Copy/Paste design pattern all over the place, which tends to produce a lot of code really fast, which some times works, but eventually will crumble under its own weight. And the Second type will put effort in understanding basic computer science concepts (such as Object Oriented and Functional programming), will dig deep into how to implement these concepts in particular language (JS in our case), when to use one vs the other. I typically define the second type as a Lazy developer -- a developer who puts effort in coming up with the most elegant solution, a developer who spends more time in order to produce less code.

Good example of Lazy kind of developers is React core team. Every couple of years or so they completely change the underlying core of the framework. Around 2015 they started with basic JS Mixins, few years later they invented Higher Order Components which was an amazing innovation at the time, to finally ditching all these cool techniques and going with good old JS Hooks approach based on functions rather than on Class components. In a way, hooks feel like a step back. But there a huge reason behind why hooks are so great -- they have smaller foot print, which makes your code a lot more elegant and efficient.

TypeScript is an attempt to hide the JS ugliness, which is indeed a good intent . But, guess what, all these JS nuances are not going anywhere -- you really, really, really need to know how all that works at a lower level. While it's not that difficult to learn yet another syntax, you still have to maintain deep knowledge of JS. To make best of TypeScript you still need to understand how it transpiles to JS. You don't have to, but you really should. Been able to write a lot of code faster in new syntax does not make you a better developer (does not make you a Lazy kind).

It's not that I'm stubborn -- if anyone wants to convince me that TypeScript is the future, let me know. But for now, JS still holds a lot for present.

Originally reposted from here: https://www.echowaves.com/post/typescript-why-not

Top comments (3)

Collapse
 
rxliuli profile image
rxliuli

I moved to ts in late 2018 and started to get very frustrated -- because I was refactoring generic libraries using ts and it contained functionally relevant functionality. For a year or so afterwards, my opinion of ts had been that it was overly complex and hard to learn, and I even once bought the domain typescript.icu with the intention of criticizing it.
But now, two years later, I believe that the front-end cannot support large-scale project development without ts. In particular, IDE support for ts refactoring, navigation, and hinting is a far cry from js! The type complexity it brings is aimed more at the library than the average developer, and it's always better for the library developer to do more than for the user to do more.

--

Some previous tweets

Having used TypeScript for some time now, I have to state here again that the type system in TypeScript is more complex than you can imagine, and if you are not ready to use it in a production system, it is better not to use it. The lack of explanation of the type system (especially native types, such as PromiseLike, which no one has talked about) makes TypeScript's type system seem like it's just for fun a lot of the time. And for slightly more complex cases, the time spent thinking about how to design types will outweigh the time spent implementing the code, so please think twice about using it!

TypeScript's type system is far too flawed for JavaScript compatibility.

See what a user said:

  1. ts can't write a way to merge objects

Here's a js method for merging objects

   function extend(dest, ... . sources) {
     return Object.assign(dest, . . sources)
   }
Enter fullscreen mode Exit fullscreen mode

With such a simple approach, ts can't write an implementation that doesn't lose type information.

The following is the declaration of Object.assign in the typescript source code, and I'm sure you can see how silly it is.

   assign<T, U>(target: T, source: U): T & U;
   assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
   assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & & W;
   assign(target: object, . . sources: any[]): any;
Enter fullscreen mode Exit fullscreen mode

According to this implementation, more than 4 arguments will just throw away the type information. ts is recommended to use at least A-Z as generic quantities... 2.

  1. some obvious type inferences are not inferred

It is common practice to use the assert method for parameter checking, a simple assert method is

   function assert(condition, msg) {
     if (condition) throw new Error(msg)
   }
Enter fullscreen mode Exit fullscreen mode

Then look at a piece of code like this.

   function foo(p: number | string) {
     assert(typeof p === 'number', 'p is a number')
     p.length // here is an error, ts doesn't know that p must be a string by this point
   }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dmitryame profile image
Dmitry Amelchenko

I don’t mean to start another religious war here, but… Based on my experience, the most messiest apps I’ve ever see were written in C++ and Java — both compiled languages. It’s not the compiled vs. interpreted — it’s all about quality of developers. Good developers tend to prefer interpreted languages and duck typing (rather than strong typing). Good developers tend to perfect the basic language skills and learn language idiomatic way of solving issue, rather than relying on static or dynamic analysis tools. Good (lazy) developers, spend time to write less code. Compiled type checking may help to some degree, but it’s wrongfully shifting focus on writing more code in different syntax (which one must learn and perfect), rather than worrying about higher level concepts like code duplication, declarative programming etc…

Collapse
 
curtisfenner profile image
Curtis Fenner

TypeScript doesn't attempt to "hide the JS ugliness" -- TypeScript has exactly the same runtime semantics as JavaScript. It's impossible to learn TypeScript without also learning JavaScript, and since valid JavaScript is truly a subset of TypeScript, if you have learned JavaScript you have also learned TypeScript.

The version history of JavaScript, idiosyncratic standard library, the way prototypes and inheritance works, automatic conversions, etc. are all components of TypeScript, because all JavaScript is also TypeScript.

The purpose of TypeScript is to manage complexity. Machine-checked types let you communicate faster:

  • You can suddenly communicate with the IDE, since the IDE now understands what properties and methods are available (e.g., auto-completion), and what arguments are legal and illegal (e.g., oops, this argument isn't nullable, or you typo'd an enum value in your configuration)
  • You can communicate with other developers faster than without types:
    • Comments can lie, types don't (as often) -- you don't have to double check things, because the compiler has double checked them for you
    • The type signature is dramatically shorter than the implementation, so you can just read that and use the module written by someone else, instead of the extensive code or docs
    • Many/most type-signatures are inferred, so they're "there" without the writer needing to actually embed them in the source code -- this is like getting documentation for your functions being written for free

And, they can also speed up development, because they can give you a clearer direction forward. Just like writing tests up front can help ensure you're only writing functions that actually solve your problems, writing types up front can ensure you're actually covering all of the surface area in a way that encourages callers to "fall into the pit of success".