Hacker News new | ask | show | jobs
by mcv 2310 days ago
We switched our project to Typescript about a year ago, because we had to handle a lot of different types of data, and it was nice to know which type you have in your hands. I wrote a bunch of code to parse anonymous JSON objects and turn them into objects of the proper types. We added interfaces for all sorts of things.

End result: checks don't work, because all our data is run-time. Most of our parameters are still of type `any`. We need to explicitly specify types everywhere that are either `any`, or they're not actually checked. I discovered recently that someone had accidentally created a type that was conceptually the duplicate of an existing type. One of those should never ever get used, but the code doesn't complain, because it's only encountering this in runtime.

So I'm inclined to agree: Typescript doesn't really add what it's supposed to add. It adds a lot of work, without providing the security we expect from it.

1 comments

I think you used the wrong tool or misunderstood how to utilize typescript. If you want guarantees of data integrity from external sources, try something like Json Schema.

Or even without that, your data should be entering the system as type 'unknown'. There's then a validator function that takes in unknown and outputs the intended type.

From there onwards, integrity is guaranteed by typescript, but only if you have the discipline to use it consistently. Otherwise, yeah, don't bother.

The second one is what I did: I've got a function that I can throw any of my anonymous data objects into, and it turns it into a typed object that knows its type and has the relevant class methods. And this worked fine with Typescript as long as nobody accidentally introduced a wrong class. Or actually it kept working fine after that, because the system simply ignored the types during runtime, so nobody noticed there was one bad class in the mix.

Anyway, we're going back to simple JSON objects. Typescript is clearly not helping in our case, and the whole process with parsing all incoming objects is fairly cumbersome without adding much value.

You might find io-ts useful [1].

“io-ts introduces the concept of a runtime type (an instance of the Type class) which represents a runtime validator for a typescript (static) type. [2]”

See:

[1] https://gcanti.github.io/io-ts/

[2] https://lorefnon.tech/u2018/03/25/typescript-and-validations...

I work with Haskell, a language that some people call "pinnacle of type systems". Guess what would happen if I use `unsafeCoerce`? Exactly the same that would happen if I use `<any>` in Typescript. All the type guarantees go out of the window.

In your code, if someone throws a bad class into the mix, it will blow up both in Typescript and in Java/C# and in any other programming language. But, somehow, blowing up in Typescript is way worse that blowing up in Java/C#. Go and tell me that when I'm not allowed to put `nulls` anywhere neither in Java nor in C#, because that's something I can do in Typescript today.

Being able to ban null values is absolutely fantastic. That's definitely a big improvement over Java, and seeing it in Typescript makes me wonder why Java allows it. In fact, seeing Option in Scala made me wonder why anyone ever thought null was a good idea.

Even if it's only a compile time check, and can therefore still be circumvented at runtime, this check for null values has still helped me out a lot. At least within a class it ensures my assumptions are consistent, which is not nothing.

>this worked fine with Typescript as long as nobody accidentally introduced a wrong class

The problem with receiving a wrong class is not intrinsic to any particular type system:

  A *a = reinterpret_cast<A*> &a;
  // have a nice gdb day
C++ doesn’t control types at runtime too, it is just bytes (runtime data) at precompiled offsets. Either you cook types wrong, or that data is designed as a set of untagged unions that get in the way of any typing, forcing to any-cast everywhere. <any> is for unknown pojos, not for already-typed values. And even if Foo is passed to makeBar(arg:any):Bar, it should treat it as pojo and still emit Bar as a result, not just ‘arg’ as it is. All typed languages do exactly the same for incoming binary data, the only difference is that you have pojos instead of byte-ptrs.

>Typescript doesn't really add what it's supposed to add.

Underspecified/force-casted types couldn’t help with these promises. It is like programming in C with a heavy preference to void pointers and va_lists.