If a developer already does input validation correctly with JavaScript, then switching to TypeScript will not add any value for them in that area.
Furthermore, my first argument (about TS giving false confidence) is that TypeScript does not make it any more likely that an unskilled developer would be able to identify and solve the problem of schema validation when compared to JavaScript... From the unskilled developer's point of view, false confidence (which TypeScript can sometimes provide) is worse than having no confidence at all (which is what JavaScript always provides).
Type checking is 100% about confidence; it gives more confidence. Confidence and correctness are two completely different things and I wanted to point out that there is such a thing as false confidence.
Edit: All of these edits to your posts after I've already replied are very confusing.
I'm more concerned about the effects of the post's title on people's programming practices than the actual content of it. HN does tend to have this effect unfortunately.
I don't want to get into this argument now though because it could last forever but hopefully it highlights why it's important to keep arguments tightly bounded and not make blanket statements when the domain is so large and complex and we can go off on a tangent in an infinite number of directions.
Ultimately, I enjoy JavaScript and I don't want future employers to force me to use TypeScript because of articles like yours (with those kinds of titles)... I was already forced to use TypeScript at my last company, it went well but it would have been even better if founders had let me and my team use JavaScript... For one, I might not have quit the company. I was tired of debugging mangled JavaScript (compiled from TS) using vim over SSH whenever there was a problem (it was a large decentralized P2P project so often that was the only way to debug it). The drawbacks of TS were definitely not worth its benefits for that specific project.
If you want to play with a powerful type system check out Raku. It offers gradual types that are a hybrid of dynamic and statically checked.
Basically, you can define a `subset` of a type with a validation predicate. Subsets can be named or anonymous and inline in function signatures.
Another thing that made me think of Raku was your discussion of NULLs. Any type container can be defined or undefined, an undefined Array container `isa` Array. But you can specify whether your annotation means to be specifically only defined or undefined members of the type. So `Int:D` is a defined integer, whereas `Int:U` is undefined, and `Int` is either.
The type specifications combined with multiple dispatch cam make for pretty code.
It's a really interesting language and, in my opinion, worth checking out. It would be great to hear your thoughts on it.
Personally, when I write a function definition, I always try to visualize the set of possible values that the function will need to handle - So given that I already have that precise set of possible arguments already in my mind as I write the function, it doesn't add any value for me to then formally generalize my function parameters as being integers or strings or some other types which are too broad to effectively constrain my function input to the required level. With static typed languages, merely specifying that a variable is an integer doesn't save me from having to think about what specific subset of integers I mean. For example, if my function only works with odd numbers as input, using the integer type definition will not offer me any additional safety.
I would argue that most functions are like this. The type definitions are never granular enough to guarantee correctness. The type system only protects you from the most basic/obvious mistakes - So obvious that you don't even need the type checker to tell you.
Static types only cover one set of bugs, but it is an extremely rewarding set. The payoff of static typing, and what TypeScript focuses on, is early feedback (did I get the name right, did I forget to convert some arguments, what can this value do?). If you focus on the "it eliminates some tests" aspect, you are completely missing the point.
> Personally, when I write a function definition, I always try to visualize the range of possible values that the function will need to handle - So given that I already have that specific range already in my mind as I write the function, it doesn't add any value...
So what the function will handle remain in your head? Or you found a better way to document them than type annotations? Do you write code that anyone else has to read now, or even you have to read later?
> The type definitions are never granular enough to guarantee correctness.
They were never meant for that purpose.
https://github.com/EXXETA/openapi-cop
This is cool for dev mode but you do not always want it in production because deep validation of all requests and responses takes many cpu cycles.
It's definitely possible (just as easy in fact). You just need to define a schema for each API endpoint. TypeScript does not physically protect you from having to enumerate all the properties and size constraints of the data one by one. In terms of the actual schema validation step, there are lots of tools in JavaScript which let you do the same thing; ajv, z-schema are just a couple of examples.
My point is that TS adds no value there. TS's value is only in static type checking. What the article is claiming is that TS somehow adds value with runtime type checking.
The argument of saying that "TypeScript adds value because it can reuse its internal type definitions for the purpose of validating remote input" is circular - It refers to a problem which doesn't exist in JavaScript to begin with.
JavaScript has no type definitions so being unable to reuse type definitions for schema validation does not qualify as a drawback on its part. The argument simply does not apply and cannot be used to claim TS's superiority.
At best you could claim that TypeScript cancels out one of its own shortcomings:
- TS shortcoming: You need to define types everywhere... That adds a lot of work! (-1 point)
- TS benefit: But you can re-use these type definitions for doing schema validation of user input as well! That saves a lot of work! (+1 point)
But the net gain over JS is 0 because:
- JS shortcoming: You need to define a schema for all your endpoints to validate user input... That adds a lot of work! (-1 point)
- JS benefit: But aside from that, you don't need to define types anywhere... So that saves you a lot of work. (+1 point)
The only real argument to be had is whether or not compile-time static typing adds value over dynamic typing.