DEV Community

Cover image for The TypeScript Experience
lucamug
lucamug

Posted on • Updated on

The TypeScript Experience

A few days ago I read a thread on Twitter where the author asked "Why wouldn’t you use TypeScript?" to people that wouldn't use TypeScript.

Reading through the answers, the perceptions of TypeScript among people that wouldn't use it are that

  • It is intimidating
  • It is an overhead
  • It makes it tedious to write code
  • It makes it harder to read code
  • It slows down development
  • It doesn't protect from runtime errors

These seem not direct critiques of static typing in general, but rather a consequence of the specific unsound static type system implemented in TypeScript, that similarly to Flow, is based on structural subtyping. This means that TypeScript’s type system allows certain operations that can’t be known at compile-time to be safe, type inference might be not correct, and it requires some level of manually-written type annotations.

In contrast, other languages like Rust, Haskell, OCaml, Elm, and F# have a sound type systems, like the HMTS (Hindley–Milner Type System), that do not require type annotations, and the types are always inferred correctly. These type-systems make sure that the code will not generate type errors at runtime. Moreover, together with other design choices, like making errors explicit in the type system ("Maybe", "Either", etc.), languages that use sound type-system are able to detect other families of runtime errors at compile time.

This is a topic already discussed at length but I wonder if there are some new perspectives.

My questions

Let me know what you think in the comment section below ❤️


Appendix - Curated overview of the Twitter thread

• Question

Looking to hear from folks who wouldn’t use TypeScript. Why wouldn’t you?

• Answers

💬

In my day job, I have to use Typescript. In my projects, I refuse.

  • Tedious writing types which 99% of the time are completely unnecessary, but required by the TypeScript compiler
  • Does not catch bugs
  • Reading code becomes much harder
  • Still needs runtime checks

💬

Because the type system is unsound and it seems to be way more complex and magical than what I would want from my type system.

💬

I spoke to a few. Found 2 types:

  • Just starting and intimidated by the wave of red
  • Experienced enough to avoid the common JavaScript pitfalls and did not get the aha moment from TypeScript

💬

Because TypeScript slows down the development of greenfield projects. It's a tool that benefits for a certain scale.

💬

Part of it was that the flexibility of JavaScript is one of its core strengths so by removing the flexibility you're removing something good.

💬

TypeScript is very useful and I find it invaluable in my day job, but it can be overkill for very small and one-off things. For other projects, there are other strongly typed compile-to-JS languages with more attractive type systems that are sometimes suitable.

💬

I'm not sure if the overhead of TypeScript is enough to justify type issues in JavaScript. Maybe in huge projects.

💬

I have tried it but had lots of problems with it. Also because some of my functions return values of different types depending on the situation. In the end, I don't get enough benefit from it. Type safety is nice to have, but I think I prefer the flexibility of JavaScript.

💬

It's hard to use a bad type system when you've used good ones in the past.

💬

I'm using it on my current project because stability is increasingly important, I wanted an excuse to learn a new thing and not get left behind, and I've been wrong before about new tools so I figured I'd give it a shot. But overall it's cost me more time than it's saved.

💬

  • Bloat (readability perhaps being the most important aspect of code)
  • Need to safeguard stuff for the runtime regardless of whatever "guarantees" I’ve gotten ahead of that time
  • Further from the metal
  • More tooling to know and maintain

💬

It slowdowns development time if you aren't used to it already. I've spent days working on things trying to type them while writing the code that could have been done in a single day.

💬

From a huge supporter of TypeScript:

  • Compile times can increase if not incremental builds or static type checking
  • "Clever" devs abusing it
  • No real guarantees, just assurances
  • A lot more code to manage
  • Some libraries have less than desirable type definitions

💬

Heavy, a bit slower, and overkill for most projects. We spend a lot of time researching good libraries to avoid writing too much code by ourselves - then why use TypeScript and write all that (mostly unnecessary) code. And most importantly - doesn't catch all bugs (not even close)!

💬

  • Too much time spent pleasing the type system.
  • Too many different configurations.
  • I don't need to have a step before running JavaScript code on Node.js, why would I add one?
  • No runtime-type checking

💬

I’ve spent more time fighting missing/broken type definitions in 3rd party libs than I care to admit.
For this reason, I won’t ever choose TS again.

💬

Cost to Benefit ratio is too high for some projects:

Benefit:

  • It's good to know the type of function argument (Especially for libraries)
  • Intellisense
  • Knowing error before runtime

Cost:

  • It's another skill to learn. TypeScript is huge
  • It has flavors. I have seen Array or string[]
  • TSConfig is another pain
  • Types can be too complex, why can't it just be a mix of primitives
  • The errors are overwhelming. I use eslint, it only warns

💬

We wrote enough Java in our careers.

💬

  • The syntax can get verbose and unreadable
  • Everything (build, test, IDE) is slower
  • Not enough libraries come with types
  • Sometimes spend an hour just to appease the type system

And that’s coming from someone (me) who is using TS on all their projects.

💬

TypeScript has to sacrifice too much to stay JS compatible. JS does not give a good dev UX by modern standards and TS does not give you a step change improvement. Try Elm!


For more answers, check the original Twitter thread.

Header illustration derived from Like emoji vector created by rawpixel.com - www.freepik.com.


🔴 Does any of these answers resonate with you and your experience❓

🔴 Do you think there is something that can be done to change the TypeScript experience, especially when compared with languages that use a sound type system❓

Let me know in the comments section below

Top comments (46)

Collapse
 
joshuakb2 profile image
Joshua Baker

I started using TypeScript when a node project of mine started to get unwieldy. It was probably less than 10,000 lines of JS code, but as requirements kept changing, the design also had to change. Major refactors were very common, and they always broke stuff because it was very difficult to keep track of everything.

TypeScript made that project so much more manageable. I use it for any project with more than 1 code file now. It doesn't prevent all runtime errors (or even all type errors), but it still prevents a ton of them. Also, the type inference is excellent and continually improving.

I don't understand why people say they're fighting the compiler so much. The types are optional! You can always just use "any" if it gets to be overkill.

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Some of the complaints listed above are - as far as I can see - very much about strictly typed languages generally.

Coming to JavaScript from strictly typed languages was liberating.... a breath of fresh air. It's like coding without the straitjacket. People should learn to work with JS as it is, instead of constantly fighting against it. TypeScript just seems like a crutch for devs not prepared to change their mindset and work in a different way.

And yes, I have used JS on large projects... and I do actually use the TS language server with the LSP plugin in SublimeText as it is faster than other language servers I've found for JS. However, I don't use any of the TS language features

Collapse
 
brense profile image
Rense Bakker

Yes I've used PHP and thought it was awesome, then I discovered that there are languages out there with less runtime errors. Btw typescript is not really a strictly typed language like Java where you are obligated to define EVERYTHING, even your function return types, which becomes a massive PITA. Typescript uses type inference, which offers the same typesafety, but less headache:

  function notComparableToJava(returnType: 'string' | 'int') {
    if (returnType === 'string') {
      return "Hello World!"
    } else if (returnType === 'int') {
      return 42
    }
    // no else clause, return type can be undefined
  }
Enter fullscreen mode Exit fullscreen mode
(local function) notComparableToJava(returnType: 'string' | 'int'): "Hello World!" | 42 | undefined
Enter fullscreen mode Exit fullscreen mode
Collapse
 
tqbit profile image
tq-bit • Edited

Tbh, I don't mind either of them. I started with JS and will always use it for my personal projects, but TS has its benefits on shared codebases. Or when I come back to a project later on.

Yeah, sure, types do create overhead and ARE tedious to write.

With every con, in my opinion, there's something to be gained though.

Types in TS (or JS with JSDoc):

  • make my code verbose, but prevent me from reading through several layers of code abstraction
  • make by IDE argue every other time, thereby forcing me to think my functions and classes through
  • take time to write, but drastically reduce time I spend in the debugger

For team projects, there's another benefit to be gained:

Your stuff doesn't suddenly crash when another dev fiddled around or updated a NPM module with a breaking change (yes, that actually happens)

I think experts call this 'Robust Code'. I just wouldn't want to spend an hour cursing at my debugging-terminal if it can be prevented by 15 minutes of typing my module.

Collapse
 
miketalbot profile image
Mike Talbot ⭐

My editor folds away types in JSDoc, it can't do that for Typescript because - not comments... JSDoc also has documentation, not just a list of types. It's my choice

Collapse
 
brense profile image
Rense Bakker

Typescript also has documentation typescriptlang.org/docs

Collapse
 
dinsmoredesign profile image
Derek D

I was a huge TS naysayer; I agreed with every single one of those bullet points. Now, I find going back to JS projects very difficult.

I think the big problem with TS is some people take it too far. Yes, it definitely can be harder to read if you use inline types, types that are named the same as your classes or you feel the need to annotate absolutely everything instead of rely on type inference where it makes sense. Things like generics can also be super confusing to new TS devs and oftentimes, they are unneeded.

If you write TS sensibly, it can be a HUGE boost to your productivity because all of the code is nicely documented by the types themselves. If makes onboarding devs 10,000x easier, as long as they understand TS decently. I don't feel like I make many type errors that TS catches and, in some cases, I find it annoying when I have to deal with things the compiler says is a problem, but simply isn't... But I recently had to go back and update a project I built years ago in Vue with plain JS and I found it a complete nightmare to figure out what half the logic was doing because there were no annotations and the inference of the IDE just threw "any" types all around.

Even on the smallest projects, I use TS now and don't really think there's a single instance I'd consider writing regular JS unless it was just a plain HTML/CSS/JS project that adding a compile step would be overkill for.

Collapse
 
jwp profile image
John Peters

Agreed

Collapse
 
reubence profile image
Reuben Rapose

Wow, I thought I was the only one not enjoying the experience of Typescript. I started developing a product in React 5 months ago. Back then typescript really felt like the right thing for a newbie because it helped me avoid tons of minor errors. But overtime as I became better at JS as a whole, i started getting frustrated with typing definitions of every variable and eventually (in order to meet my delivery date) I even started completely skipping type checks by filling in "any" as the type.

Soon after I started to wonder what is the point of typescript if I'm barely even using it at this point. I thought I was just following bad programming practices. But after reading this post & comments I'm convinced typescript is not at all a necessity for every damn project.

Collapse
 
jwp profile image
John Peters

Many Javascript folks tend to lean too deep into Typedefs when they only need to write functions that tell input and output types.

Doing that allows intellisense for every function.

Collapse
 
reubence profile image
Reuben Rapose

Could you help me out with some examples?

Collapse
 
brense profile image
Rense Bakker

Its a small minority of coding cowboys, usually former backend devs who switched to javascript at some point. You can tell usually by the comparison with Java. Type defs used to be a problem but not since 2020, all maintained libs on npm either have built-in type defs or they're available through @types. Often these coding cowboys are very passionate about some unmaintained lib that hasnt been updated for 9 years and is full of security exploits. Typescript is a superset of JavaScript, so people complaining how the syntax of JavaScript is better than Typescript, you can just immediately ignore 😛

Collapse
 
reharik profile image
Raif Harik

I don't know if it's an issue with ts or tooling or what, but 9 times out 10 when there is an error it is super difficult to understand what type is expected and/or how you have failed to satisfy it. There is often so many layers of inheritance, extension or composition that knowing what you need to provide can eat away your day. And sanity. Even when it is a simple type and a simple violation the error message is super verbose.
After about 9 months if full time ts dev, I can get around just fine and can decode errors pretty well, but it wasn't easy and definitely wasn't pretty.
My other major complaint is that while you get all the verbosity of a strongly typed language, you get none of the good parts. E.g. introspection/reflection, metadata about the types you are using. Instead of helping me to write intelligent tools, I find it prevents me from writing reusable code by requiring use of generics, which in c# I found to be one of the greatest assets, but in ts I find to be a black hole.

Collapse
 
brense profile image
Rense Bakker

If you hover a function or variable in visual studio code it will tell you exactly what type it expects:

(method) RTCPeerConnection.addIceCandidate(candidate?: RTCIceCandidateInit | undefined): Promise<void> (+1 overload)
Enter fullscreen mode Exit fullscreen mode

not sure what you mean by it being super verbose, when i have a type violation i see something like this which tells me exactly what i did wrong:

Argument of type '{ bla: string; }' is not assignable to parameter of type 'RTCIceCandidateInit'.
  Object literal may only specify known properties, and 'bla' does not exist in type 'RTCIceCandidateInit'.
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jwp profile image
John Peters

The number of layers of inheritance do not need to be deep. Chances are high the deep inheritance aspect is bad implementation.

Collapse
 
etienneburdet profile image
Etienne Burdet • Edited
import { OldComponent as _OldComponent } from 'components';
const OldComponent: any = _OldComponent;
Enter fullscreen mode Exit fullscreen mode

I won't lie, there are things I really like with TS, but I wish I could spend less time making the compiler happy.

If someone wants to make a sound type system for ES6+, I'm all-in for it… 😂

Collapse
 
brense profile image
Rense Bakker

Why on gods earth would you do that?

Collapse
 
etienneburdet profile image
Etienne Burdet

Because OldComponent is not typed (and we don't want to type it now), so it creates problem with types of children, spread props etc.

Thread Thread
 
brense profile image
Rense Bakker

Not sure how that is possible? Afaik if you can import your untyped js code like that, typescript is going to infer types from it as well... If it's an untyped module and type inference is not possible for some reason, you can use something like this:

// components.d.ts
declare module 'components' {
  export const OldComponent:any
  // or just give it a proper type asuming its a react component?
  export const OldComponent:() => JSX.Element
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
corscheid profile image
Corey Scheideman • Edited

Ahh I remember this Twitter thread. I laughed so hard at the Bubble Sort type 🤣 Part of me was like... WHY... and part of me was like holy sh1t that is ... impressive - I did not know this was possible in TypeScript.

Collapse
 
patoi profile image
István Pató • Edited

We've rewritten a large code base to JavaScript + JSDoc from TypeScript:
SPA, frontend, Vue.js v2 + TS ➡️ Svelte + JS + JSDoc: half size of "runtime" JS and source code, three time faster build

  • smaller source code
  • readable code
  • increased maintainability
  • booting new developers is faster
  • more developers available, because you don't need to know TS
  • fewer dependencies: less breaking change, less vulnerability
  • less tooling

youtu.be/xLDVfBUgD8U

Collapse
 
ecyrbe profile image
ecyrbe

In contrast, other languages like Rust, Haskell, OCaml, Elm, and F# have a sound type systems, like the HMTS (Hindley–Milner Type System), that do not require type annotations, and the types are always inferred correctly.

I beg to differ. Typescript has one of the best type inference out there. You can write almost everything but function parameters without any type annotations in typescript.

To take one of the examples, Rust requires a lot more typing. (Coming from a rust developper).

One Guy saying that he dislike typescript because he could not type it's return type because he wanted to return different types. He did not need to. Typescript would infer the return type without any issue.

Some of the issues raised come from obvious misuses of typescript.

Collapse
 
tbm206 profile image
Taha Ben Masaud

TS cannot infer the type of chained/composed functions; e.g. with lodash/fp/compose. That's pretty lacking if you ask me

Collapse
 
jwp profile image
John Peters

Lodash is not TypeScript. Any missing intellisense you expect is an issue with a bad Typedef file. It has nothing to do with Typescript.

Collapse
 
ecyrbe profile image
ecyrbe • Edited

It's not an issue with typescript but with library authors of definitly typed librairies.
Take a look at fp-ts that handles chaining just well.

Collapse
 
rajeshroyal profile image
Rajesh Royal

When I don't knew it, I hated it. Now I do not want to go back ✌️

Collapse
 
jbartusiak profile image
Jakub Bartusiak

I absolutely love the example with bubble sort in type system. I appreciate it might be hard to learn, but it's extremely powerful, and makes big projects much easier to manage.

Collapse
 
jwp profile image
John Peters

Your arguments are wrong in my mind and lumping C# in the same sentence discussing 'structural typing' is highly confusing.

Your obvious hatred for TypeScript simply means you need to bar yourself from those jobs.

In the meantime TypeScript shops get stronger and have none of the issues being red flagged here.

Collapse
 
lucamug profile image
lucamug • Edited

Thank you for the comment. I found some sources associating C# type system with the TypeScript type system, but others do not. So, until that part is clearer I will remove both C# and Java from the list, thank you for pointing it out.

I don't hate TypeScript, I actually have been a promoter of it and pushed to have it adopted in all our JavaScript code at work. I think it is a valuable asset if you have a large JavaScript project.

Here I am trying to understand why people have these experiences with TypeScript.

Does any answers reported in the post sound familiar to you? Do you think there is something that can be done to change the TypeScript experience, especially when compared with languages that use HMTS?

Collapse
 
peerreynders profile image
peerreynders

The comparison with C# comes up because

  • Anders Hejlsberg is the lead architect of C# and TypeScript
  • by implication:

"TypeScript began its life as an attempt to bring traditional object-oriented types to JavaScript so that the programmers at Microsoft could bring traditional object-oriented programs to the web."

That evokes the whole 2012 "ASP.NET with C#" theme. But at the very least it does imply that TypeScript was designed to feel familiar to established C# developers.

But then "TypeScript’s type system has evolved to model code written by native JavaScripters. The resulting system is powerful, interesting and messy."

… which lead to the value space (variable declaration space) and type space (type declaration space) divide - and lots of syntax to extract information from value space into type space.

const RNA_COMPLEMENT = {
  G: 'C',
  C: 'G',
  T: 'A',
  A: 'U',
} as const;

type DnaNucleotide = keyof typeof RNA_COMPLEMENT;
Enter fullscreen mode Exit fullscreen mode

Some of the tension comes from the fact that TypeScript offers more value (as in gets less in the way) as a JavaScript type linter than as a programming language.

Being able to "Just use JavaScript" (rather than having to compile it), while being able annotate types succinctly for occasional type linting should silence most criticisms. At this point JSDoc TS is seen as verbose (though @type gets close) and not all of TypeScript's features are necessarily easy to access from JSDoc/JavaScript (though that hasn't stopped projects from adopting it (most notably Preact for performance reasons)).

FYI: Deno 2.0 will skip type checking by default to improve start up performance.

I don't believe that TypeScript would have gotten as much traction as a pure type linting tool—as a programming language it brought a sense of familiarity to those with a background in statically typed languages and who were sceptical about trusting dynamically typed code.

Ideology 3:11


Type branding is sometimes used to approximate nominal typing:

Thread Thread
 
lucamug profile image
lucamug

The "Ideology" video linked is very nice.

Related to it, it would be interesting to roughly categorize people that answered the Twitter thread in

  • People that only experienced JS
  • People that experienced JS and TS
  • People that experienced JS, TS, and a statically typed language like Java, not based on the Hindley–Milner type system
  • People that experienced JS, TS, and a sound static language like Haskell, OCaml, Elm, or F# based on the Hindley–Milner type system (where type annotations are mostly optional)
Thread Thread
 
peerreynders profile image
peerreynders

On a side note:

A Gentle Introduction to Haskell, Version 98

"It's usually helpful to write down the type of new functions first;"

I always thought that it is useful to actually separate the type from the implementation - as opposed to the C-style conflation of both. So something like

/** @type {(string, boolean) => number} */
function sbn(s, b) {
  /* ... implementation details ... */
}
Enter fullscreen mode Exit fullscreen mode

seems perfectly reasonable - though familiarity with the mainstream, conflated syntax

function sbn(s: string, b: boolean): number {
  /* ... implementation details ... */
}
Enter fullscreen mode Exit fullscreen mode

creates a bias towards s: string "belonging together" even though they are just distinct aspects of the same positional argument:

  • s is the name the value of the positional argument is bound to
  • string is the type the positional argument is expected to be
Thread Thread
 
lucamug profile image
lucamug

"It's usually helpful to write down the type of new functions first;"

Yes, it is interesting to note that devs that use languages where type annotations are optional end up with a mindset of writing type annotation first and the implementation after.

Programming languages influence the way we find solutions.

Collapse
 
jwp profile image
John Peters

The Javascript community in general, did not like TypeScript. They felt their comfort zones fading away. Understandable as Assembly Language programmers did the same thing when 2nd Gen languages arrived.

Javascript folks also tend to discount Java, C## and C++ people feel TypeScript is the least problematic way to join the Javascript family.

As far as really knowing any Language is to spend around 1.5 years using it daily. Only then will they really have a feel for what it can do.

Collapse
 
almaaaaa profile image
vinz243 • Edited

Some points are fair enough (Sometimes spend an hour just to appease the type system, The syntax can get verbose and unreadable) but other are not very well thought.

Not enough libraries come with types

This is utterly false. Nowadays every popular one has typings, and even less popular have them now. And tbf should you be using unknown and obscure packages on npm?

I don't need to have a step before running JavaScript code on Node.js, why would I add one?

This is just a useless point, because this is the point that is being discussed. Imagine : Should we ban x thing (because y) ? No I don't think so because I don't want to ban something, so why should we ban it?

Does not catch bugs

It does... More often than not. It catches most mispells and typos, and inattention issues. Which is a lot (and the most painful part of vanilla js to me)

It has flavors. I have seen Array or string[]

Comparing it to vanilla js ??

Too many different configurations.

If it wasn't the case then they would be complaining about the even greater lack of flexibility.

No real guarantees, just assurances

what does this blanket statement even means ?

It seems to me that these people want their cake and eat it too. Sure it's not perfect, and it's not THE solution that will eliminate all pain from frontend dev. It has its pros and cons as does every tool.