DEV Community

Discussion on: TypeScript is a waste of time. Change my mind.

Collapse
 
stereobooster profile image
stereobooster • Edited

UPD: I turned this thread into article dev.to/stereobooster/type-system-f...

Ok let's start constructive conversation by fixing some terminology: JS is typed language, it is dynamically-type-checked language (or some people short it down to dynamically typed). JS has types: string, number, bool etc. JS has type errors (not much, but still)

null.func // Uncaught TypeError: Cannot read property 'func' of null at <anonymous>:1:6
Enter fullscreen mode Exit fullscreen mode

JS has implicit coercion, which may create impression that there are no types in JS. Read more here.

So the question of use or don't use TS boils down to: do you want to do static type checking or not? (Dynamic type checking always there). And there is a trade of: you need to write a bit more code (type annotations) in order to make static type checker work. It's up to you to decide if it worth it or not.

As well, you may be confused by soundness of type system. Some type systems are sound e.g. they can prove there are no type errors. TS is not sound (any type), but you can bulletproof it with tsconfig, by setting all strict checks to true. And by prohibiting usage of explicit any.

However, because TypeScript compiles down into JavaScript, regardless of how carefully designed your types are, there always is the chance that a different value type sneaks into a JavaScript variable.

You can make a bridge between static type system and dynamic type system. Check that type are valid dynamically on the input (which is unknown and uncontrolled) and rely on the static type checker through the rest of the programm

for example:

const makeSureItIsAString = (x: any) => {
    if (typeof x !== "string") throw new TypeError("Not a string")
    return x;
}
const nickname = makeSureItIsAString(userInput())
// we are sure that nickname is a string in this part of the code
Enter fullscreen mode Exit fullscreen mode

read more about io validation here

Collapse
 
cubiclebuddha profile image
Cubicle Buddha

Thank you @stereobooster for mentioning io-ts for strong typing at the boundaries of your application. I really think it helps eliminate all of the problems that Lucas mentioned.

Collapse
 
bettercodingacademy profile image
Better Coding Academy

Thank you for your input! Allow me to respond and clarify:

JS is typed language, it is dynamically-type-checked language (or some people short it down to dynamically typed).

Yes, I know. However, I wanted to differentiate between TypeScript / Flow-based JavaScript and JavaScript code that doesn't have TypeScript / Flow. I was first going with "plain", but then again, technically you can have JSX and other non-JS features without static types, so that's why I settled with "untyped".

And there is a trade of: you need to write a bit more code (type annotations) in order to make static type checker work. It's up to you to decide if it worth it or not.

Yes, I agree completely. However, I also believe that it is not worth it in the majority of cases, and that many people are misguidedly using TypeScript believing that it will save them time when in fact it only slows down development in both the short and long-term.

TS is not sound (any type), but you can bulletproof it with tsconfig, by setting all strict checks to true. And by prohibiting usage of explicit any.

This is true; however, in my experience this only leads to lots of red squiggly lines. It's impossible to do completely strict types in TypeScript / JavaScript, and there's always going to be that one case that cannot be fixed with this. Before you know it, you've got half-types and hacked code all over the place, and that's something that's not satisfying at all, especially when you've spent an extra 20-40% of development time writing up types, downloading type libraries and exporting interfaces.

You can make a bridge between static type system and dynamic type system. Check that type are valid dynamically on the input (which is unknown and uncontrolled) and rely on the static type checker through the rest of the programm

You sure can, but I would argue that if you want true type safety and security you should look at a statically compiled, more lower-level language. For example, in many large companies the API that interacts with the database is almost always written in a statically typed language such as C++, C#, Java, etc. - I don't think that TypeScript is the solution here. Plus, importing a function makeSureItIsAString seems like overkill just to make TypeScript support complete.

Once again, thank you for your detailed response, and I hope my response has been appropriate!

Collapse
 
projektorius96 profile image
Lukas Gaucas

All those folks who are on TypeScript side are biased or at least part of TypeScript living standard . I agree with @Better Coding Academy that TS is scam & will be scam because it takes all its fashion clothing (generics, type checking, etc.) off once transpiled to JavaScript before being compiled into something more of assembly taste . I assume nearly best not too much geeky trade-off for JS lander would be to try C# , of course , this is just my personal opinion .

Collapse
 
cubiclebuddha profile image
Cubicle Buddha • Edited

This article has some misinformed opinions being reported as fact. I don’t mean that as an insult, I am just sad that there is no empiricism involved. Allow me to clarify:

For example, in many large companies the API that interacts with the database is almost always written in a statically typed language such as C++, C#, Java, etc.

All of those languages are weakly-typed when it comes to the MOST important aspect:

// valid C#
String myStr = null;

// invalid TypeScript 
const myStr: string = null;
Enter fullscreen mode Exit fullscreen mode

Do you see how big of a problem it is that C# allows reference types to be implicitly nullable? That means that you can never know if your data is there are not. :( But with TypeScript you can have confidence in your code. The only languages that have strict null are TypeScript, Kotlin, and Swift. Can you see now how your subjective statement above is both incorrect and misleading? I feel like it’s the equivalent of “the cool kids are using C#.”

Plus, importing a function makeSureItIsAString seems like overkill just to make TypeScript support complete.

There’s no reason to write functions like makeSureItIsAString when libraries like io-ts do all of that work for you of ensuring type accuracy at compile time AND runtime. So if you’re looking to build an enterprise-grade app, io-ts or tsoa are wondeful tools to eliminate bad data from even getting through the front doors.

Thread Thread
 
stereobooster profile image
stereobooster

Let's use softer tone. Everybody has holes in their knowledge, it is ok as far as person willing to learn and take part in reasonable conversation. (Conversation was pretty reasonable so far. ❤️@parkroolucas. The title is a bit harsh, but I guess this is meant to be clickbait).

All of those languages are weakly-typed when it comes to the MOST important aspect:

Weakly-typed/strongly-typed is ambiguous terms. See here

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha • Edited

The title is a bit harsh

Yes. How many of these anti-TS articles are there? But when you look at the usage rates, most of the developers who try TS are interested in using it again.

Thread Thread
 
stereobooster profile image
stereobooster

I totally get you ❤️. What I'm saying if we all switch to this tone, it would be hard to have constructive conversation ¯\_(ツ)_/¯ (Yes author used the provocative title and text, yet somebody should stay cold-blooded)

Collapse
 
stereobooster profile image
stereobooster • Edited

JSX is typed as well - it's just React.createElement() and you can attach dynamic type checking with PropTypes. Or in typescript

Or you can use them both like described here.

Let's stick to correct usage. Untyped means there are no types or what is the same, there is only one type. For example, assembly is untyped language it has only one type - bit strings, Lambda calculus is untyped language it has only lambdas.

It's impossible to do completely strict types in TypeScript / JavaScript, and there's always going to be that one case that cannot be fixed with this

In general it should be possible. The other question if you want or not. Don't mix up two argument.

typed language such as C++, C#, Java, etc.

You realise that all those languages are not type safe?

Java unsound, C unsound

Haskell has a sound type system. The type system of C (and thus C++) is unsound.

-- cs.uaf.edu/~chappell/class/2016_sp...

C# unsound

No, the C# type system is not sound, thanks to array covariance, my least favourite feature:

-- stackoverflow.com/questions/239391...

It means it is totally possible to write program in all of those language which will crash at runtime because of type error.

Don't confuse static types with type system soundness.

Plus, importing a function makeSureItIsAString seems like overkill just to make TypeScript support complete.

You don't need them everywhere you need them only to validate io e.g. user input, server response etc. There are libraries like, io-ts which helps to simplify this process.

Thread Thread
 
bettercodingacademy profile image
Better Coding Academy

In general it should be possible. The other question if you want or not. Don't mix up two argument.

I wouldn't say "in general", I would say "in theory" - however, in practice it is commonly the case that you don't write 100% of the code you use; and as such, you cannot confirm the validity and "typeability" of the code you are given.

You realise that all those languages are not type safe?

That was not my point, and I overstepped when I said "true type safety". Obviously TypeScript does not provide sound type safety and neither do the languages I've listed; however, they do have much stronger, native checks for static typing that are built into the languages, as opposed to TypeScript which still transpiles down before then being interpreted - quite a few layers there where errors can occur.

You don't need them everywhere you need them only to validate io e.g. user input, server response etc. There are libraries like, io-ts which helps to simplify this process.

Could you give an example of when you would need to validate and when you wouldn't? Seems weird to have to validate whether user input is a string, for example.

Thread Thread
 
stereobooster profile image
stereobooster • Edited

Could you give an example of when you would need to validate and when you wouldn't?

If you expect string and you read from the html input you will get string. But if you, for example, read state from URL and decode it and expect some arguments to be numbers, things can go wrong here. Or if you, for example, use JSON.decode to get response from the server, you need to make sure that response is in correct format.

I would validate all user input, I meant to say, that reading IO is typically not that big compared to other logic of application.

however, they do have much stronger, native checks for static typing that are built into the languages, as opposed to TypeScript

Why do you think so? Typescript is quite advanced type system it is based on latest research (and written by the same people who wrote C#, Anders Hejlsberg for example). So this claim needs a bit more evidence.

The fact that it compiled to JavaScript doesn't make it unsafer. All checks happen before compilation. The same for native programs, check happens before compilation, one of the compilation steps is type erasure (unless you use something like Reflections or io validation or pattern matching on boxed values). After type erasure you deal with untyped assembly code. Do you think assembly is more safe than JS? (rhetorical question)

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

...in my experience this only leads to lots of red squiggly lines.

I don't know much about TS (and not a fan of JS, but let's leave that out of this), but I do know a lot about both C++ (static typing) and Python (dynamic typing).

If your code is filled with red squiggly lines from any linter or other static analyzer, you can almost certainly depend on your code being the problem, not the analyzer!

The same flawed logic in what I just quoted at the top is the reason C++ developers are afraid to turn on -Werror: "but, but, my code won't compile, it'll just give lots of errors.

I've seen that issue in nearly every language I've worked in, so it simply tells me that if someone is working in TS, and is avoiding strict mode because "too many red squiggly lines," you can bet the house they've been writing bad code. Chances are, in fact, they're using TS as if it were nothing more than JS-with-type-hints-on-top...and utterly eschewing the patterns and logic one must follow when working with types.

All that to say, if someone's gripe is too many red squiggly lines, I wouldn't trust the quality of their code in that language.

Collapse
 
sompylasar profile image
Ivan Babak

It's impossible to do completely strict types in TypeScript / JavaScript, and there's always going to be that one case that cannot be fixed with this.

You have to understand where it is impossible: at the I/O boundary where your typed system talks with the outside world. Types help to make sure statically that the typed part of the program does not contain type errors. If the I/O boundaries are clearly delineated, and the data is cleanly marshalled from the untyped world into the typed world, you will clearly see the benefit if the typed world is large. If the only thing you do in your programs is manipulate the untyped data, it is easier without types.

Collapse
 
cubiclebuddha profile image
Cubicle Buddha • Edited

I’m really disappointed to hear this same subjective phrase again:

when in fact it only slows down development in both the short and long-term.

I was hoping to find some objectivity. At a minimum, can you please try to convince me that TypeScript slows you down more than it speeds you up?

Consider the fact that I wanted to rename a variable yesterday and VSCode let me do it (and it can only do it accurately because of TypeScript). It changed the variable in 78 files. And this is important: it didn’t just do - “find and replace...” it did it intelligently. To refactor a variable name in JS would have taken a very long time and I would have had to regression test the entire codebase to make sure I didn’t break anything. I would estimate that a full regression test of my application would take 1.5 days.

And you also forgot about the fact that TypeScript helps to communicate your meaning to future developers. Isn’t that important?

So if it helps significantly with refactoring and helps you be a better coworker, then why is it a waste of time?

Thread Thread
 
pb8226 profile image
Paul • Edited

Good point, ease of refactoring is a place where static typing helps.

Thread Thread
 
xcs profile image
XCS • Edited

My experience was the same: I was forced to do numerous refactorings over big codebases, all done by pressing two buttons thanks to TypeScript, refactorings which would otherwise have taken hours with plain JS. TypeScript is a godsend for the JS ecosystem in my opinion.

Thread Thread
 
wmertens profile image
Wout Mertens

Vscode refactors plain js just fine. Typescript does not help with that.

Thread Thread
 
g1itcher profile image
G1itcher

I don't think that's true across multiple files and variables. Especially when multiple classes/interfaces have the same variable names

Thread Thread
 
wmertens profile image
Wout Mertens

Ah - you're renaming a variable in an interface? In that case, yes, probably vscode can do that thanks to typescript, and wouldn't be able to do it without it.

OTOH, all the times I did this, I did a global search&replace, eyeballing to make sure, and having the tests for extra verification.

Thread Thread
 
jsalinas11 profile image
Jordan

Uh, wait why are you using a single variable across 78 files? If I have to understand 78 files to understand a feature it sounds like you have bigger problems.

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha • Edited

That’s a lot of judgement Jordan. You seem to be making some assumptions.

“uh, wait why are you using a single variable across 78 files? If I have to understand 78 files to understand a feature it sounds like you have bigger problems.”

For a moment, suspend your assumptions and consider the fact that we had a valid reason for updating the the name of a property on some data. The reason the variable change effected 78 files is because we renamed a property on a data object that we use throughout the entire system. And since we have many api tests, end-to-end tests, unit tests, and more it caused a large change. But that’s the beauty of TypeScript... I can make a change that effects the entire system without causing any quality concerns.

So while your assumptions involve a change to one feature, in reality this change effected all features. When you take a functional / data-oriented approach it’s not uncommon to have many transformation functions that manipulate the data. And since I currently work on a data visualization UI, there are a great many ways that the users want the data to be transformed.

Does that clarify how one variable name can ripple out? Hopefully it communicates how TypeScript allows my team to continuously refactor with safety and without having to spend a bunch of time updating tests just because we learned that we originally misspelled a property on the data an API returns.

Thread Thread
 
jsalinas11 profile image
Jordan

Yeah, you're right I did judge. Sorry. I don't know your codebase, I just find it odd that a single variable would exist across 78 files. Feels wrong to me. Something like KISS or maybe SRP come to mind. But again I don't know your codebase.

Thread Thread
 
wmertens profile image
Wout Mertens

I think what they were doing is renaming a key in an interface, like going from data.online to data.isOnline

Thread Thread
 
xcs profile image
XCS • Edited

Or adding data.timestamp. With TS you automatically get notified of all the places where this data has to be set and also you now automatically know everywhere you use data that it also has a timestamp property. Also, TS ecosystem goes further than that, you could have Protobuf definitions that might be updated because data is serialized and sent over the network to multiple other services, and with the updated TS typings everyone just knows about this change and can update their code accordingly. And yes, this data interface could be used by hundreds of files across multiple services and git repos.

Thread Thread
 
rjmunhoz profile image
Rogério Munhoz (Roz) • Edited

Vscode refactors plain js just fine. Typescript does not help with that.

Actually, I might be mistaken, but VSCode uses tsserver to better understand your code and do stuff like refactoring, IntelliSense and stuff.

TypeScript isn't only able to perform static type checking on explicit types, it also infers types quite well. It's even possible to write plain JS, enable allowJs and checkJs on your tsconfig.json and let it infer and type-check stuff for you.

This also takes me to another point: in my experience I hardly type stuff other than function parameters; typescript can, usually, infer the rest. So arguments like "you write more code" get a bit weaker, IMHO

Thread Thread
 
badsyntaxx profile image
badsyntaxx

I hardly type stuff other than function parameters

This is what I don't get. If you're just gonna mostly do normal js stuff anyway, then whats the point? Shouldn't you just comment your function and describe the expecteds anyway?

This isn't rhetorical nerd snark. I'm really want to know.

Thread Thread
 
xcs profile image
XCS

One thing to note is that most of the stuff is inferred. So by typing function parameters, almost all data in your app will have an inferred data type (because knowing the parameter types will automatically result in knowing the return types).

Collapse
 
kayis profile image
K

I learned that if a type checker just let your app crash "right before a bad access" it is equivalent to untyped.

Collapse
 
shavyg2 profile image
shavyg2

Lol, no

Collapse
 
stereobooster profile image
stereobooster

If it allows incorrect type to pass type check process it is called unsound type system, not untyped.

Thread Thread
 
kayis profile image
K

That's not what I meant.

JS says right before an access on undefined that it is undefined. So the dynamic type check could as well be not there.

Thread Thread
 
stereobooster profile image
stereobooster

This exception itself is dynamic type check

VM219:1 Uncaught TypeError: Cannot read property 'sd' of null
    at <anonymous>:1:6

JS type checked it for you and because type mismatched, the only thing it is left to do is "panic" (throw exception)

Thread Thread
 
shavyg2 profile image
shavyg2

It's crazy how clueless some people are. What is confusing is they'll sound so sure when they are talking tho. If the language wasn't type checking it wouldn't crash it'd just keep going with wrong values. Dude said might as well just not be there. If I had a number 98, I think is "a" if I used as a char it would say "a" but because it's typed check, it checked to see how I was using it and crashed so I the developer can be informed and correct my mistake or cast it to explicitly tell the run time no I did this on purpose.

Thread Thread
 
kayis profile image
K

Sounds reasonable, thanks.

Got my definition of dynamic typing == untyped from a static typing fan prof. at university.

"Either you use static typing or no typing at all, everything else is BS."

Thread Thread
 
stereobooster profile image
stereobooster • Edited

this kind of education. I feel you. I had something similar.

(this is addressed to your professor)

What about IO validation?.. This kind of type checking can be done only at runtime. And all "super" static languages do it at runtime, including such notorious examples as Haskell and OCaml.

I mean even if you use static typing, some checks are impossible to do statically.

Also how to interpret no types? If you would take a look at the parser of almost any language, you would see that parser knows about types. It knows that value in quotes is a string, that value from digits is number, etc. In dynamic languages, there can be no declarations of types of function arguments, but there are always types of values. As well even if type declarations omitted they can be inferred by powerful types systems (to some degree).

What about a gradual type system? Which allows having only some of the types declared.

Thread Thread
 
shavyg2 profile image
shavyg2

It's just crazy, I mean I'm sure some of you have worked with JavaScript and feel a bit confident commenting. In my mind I'm like but you see typeerror in JavaScript when you use the wrong type some where or it says type error can't call blah on foo. Then you go on to say it has no types. It's like hearing there was a car crash and being like, I bet you no cars where involve. I just don't get how people say stuff like that. I have a few friends trying to learn programming and they like it's hard man, and I'm like naw people just make it confusing because they say so much nonsense and I don't even understand why. Books and paid online courses are the best route sadly because the internet...

Collapse
 
luxcium profile image
Benjamin Vincent • Edited

This is indeed possibly interesting forSure:
null for sure

I am now adicted and dependent to the type sytem... when I do small stuff in JS I always end up changing my extension to .ts because it is way more easy... so the tradeoff you are talking about is exactly waht it is (a trade off) → I am lazy as F'ck so I prefer TypeScript but... it imply that I need to work more so I can relax about the types... The main point is about the information the type brings more than the safety or what else (at leat to me)... if I wasn't lazy and at the same time concerned about safety I would do everything in RUST perhaps...

Collapse
 
noderaider profile image
Cole Chamberlain • Edited

With a very strict configuration, TypeScript is more type safe than C#. In C# a reference type can be null. Not the case in TypeScript. With any language you could read in unknown data. It's no different with TypeScript. Use some assertions.

It may not save you time coding (I'd argue it does - see intellisense), but it 💯 saves time in prevention of runtime bugs. If you're seeing red squigglies and don't need to fix them to run your app, you're not doing it right.

If you're explicitly typing everything, you're not doing it right. I'd argue that the TypeScript example with context you posted is more readable due to the ability to read exactly what the context is via the generic type parameter.

TypeScript unit tests are usually shorter and superior to JavaScript's due to there being no point to testing a bunch of silly stuff like does this module export a function or not.