3 ms·
The title is misleading because TypeScript does not implicitly do any kind of runtime type checking on data which was sent by remote clients - If the client and
by cryptica 7y ago
The title is misleading because TypeScript does not implicitly do any kind of runtime type checking on data which was sent by remote clients - If the client and server both happen to be written in TypeScript by the same team, the TypeScript type system can give those developers false confidence that the API endpoints on their server enforces runtime type validation on remote user input (I've seen this too many times), but it does not.
To implement API endpoints correctly in TypeScript, you're supposed to assume that the arguments sent by the remote client are of 'unknown' type and then you need to do some explicit schema validation followed by explicit type casting. Some TypeScript libraries can make this easier but it's misleading to say that this is a native feature of TypeScript; in fact, it is no different from doing explicit schema validation with JavaScript (there are also libraries to do this). You should always validate remote user input regardless of what programming language you use.
Merely getting the compile-time static type checker to shut up because the types in your client code match the types in your server code is not good enough unfortunately - In fact, it may conceal real issues by giving developers false confidence that runtime type validation is happening when in fact it is not. A hacker could write a client in a different language and intentionally send incorrect input to crash your server unless your server explicitly validates the schema.
The reality is that there is no guaranteed type continuity/consistency between the client and the server. Any tool which gives the illusion that there is any kind of continuity is deceptive by design.
This is why I like plain JavaScript; it requires real discipline and it doesn't give any sense of false confidence. Developers should always be on their toes. The only way to improve code quality and security is by exercising more caution, not using more tooling.
The benefit pointed out by the author of this article is in fact one of the few genuine gaps in TypeScript's type safety capabilities. Praising TypeScript for this fictitious feature is only going to give developers false confidence that TS somehow takes care of input validation for them and this is going to lead them to getting hacked.
- gary_bernhardt 7y ago(I wrote the article.) Our system uses io-ts to dynamically validate all incoming and outgoing API data. The static API types are guaranteed to match the io-ts codecs, so the runtime validation will match the static types. Re: "it's misleading to say that this is a feature of TypeScript": I didn't say that. TypeScript makes this kind of static verification possible. It's impossible in JavaScript. Re: "The benefit pointed out by the author of this article is in fact one of the few genuine gaps in TypeScript's capabilities": yes, it's a gap in TS. Again, TS makes it possible (as opposed to JS). io-ts (mentioned explicitly by name in the article) backfills the type erasure shortcoming for our purposes, at the expense of being more verbose and producing worse error messages when compared to first-class reflection in a non-type-erasing language. Re: "going to lead to them getting hacked": no, io-ts isn't going to lead to that more than any other runtime validation scheme. If someone believes that TS' static types provide runtime guarantees, yes, they could write highly insecure API code. But it's hard for me to imagine someone getting to an experience level where they can write a server-side router that's generic over all possible API endpoint payloads, while at the same time not knowing that TS erases types at runtime. Erasure comes up early in the process of learning TS because it leads to surprising behavior, like objects at runtime having properties that aren't present in their static type.
- cryptica 7y ago>> It's impossible in JavaScript. 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.
- gary_bernhardt 7y agoThe post isn't about dynamic validation; it's about static type checking of APIs, which is impossible in JavaScript.
- cryptica 7y agoMy point is that static type checking of APIs does not solve any new problem which static type checking in general does not already solve - That's why I don't agree that it solves API woes specifically. My argument is that it adds no value in that area. 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.