5 ms·
Can someone comment on the difference in reliability between using typescript and a natively statically typed language like haskell or scala? Is there any? Or i
by jtmarmon 10y ago
Can someone comment on the difference in reliability between using typescript and a natively statically typed language like haskell or scala? Is there any? Or is the type safety really as good when you use ts
- jiaweihli 10y agoI haven't worked too much with Haskell, but I've spent some time with Scala - they have pretty advanced type systems. Typescript can't match them 100%, but it's getting there. e.g. It doesn't have type variance, but it does have f-bounded polymorphism (which is unheard of in most mainstream languages). The language is powerful enough to build your own constructs. I maintain a Typescript library[1] that emulates Scala options/trys/futures. For day-to-day work, Typescript is a joy to work with. I describe it to others as the child of Scala and Ruby - pretty powerful type system but with a large community. [1] https://github.com/jiaweihli/monapt https://github.com/jiaweihli/monapt
- virtualwhys 10y agoThey're different things, TS is a transpiler while Haskell (GHCJS) and Scala (Scala.js) compile respective host languages to javascript. In a perfect world you'd go with the latter, but there's overhead involved (relatively slow compilation and large generated binaries) that is mostly absent in TS. Also worth noting that TS' community is gigantic in comparison to that of Scala.js and GHCJS.
- jtmarmon 10y agoI was asking about the native languages themselves and their typesystems, not the compile-to-js versions of those languages. Regardless, I don't see much of a difference between TS -> JS and haskell->JS and scala -> JS. It's all from one language to another. the fact that TS is still considered a form of javascript is kind of irrelevant other than for semantics
- virtualwhys 10y ago> I was asking about the native languages themselves and their typesystems, not the compile-to-js versions of those languages. Are they different? If language X can be expressed in its entirety as language Y then we can speak about X and Y interchangeably -- that's literally the point: full interop between client and server. Anyway, there's a world of difference between TS and GHCJS, Scala.js, Clojurescript, Js_of_ocaml, etc. One speaks javascript, the others speak both. As for reliability, in so far as TS is typed it will provide the compile time guarantees that its type system provides; not surprisingly the same goes for Scala.js, GHCJS, etc. So, the decision point probably hinges more on aforementioned overhead, size of community, and tooling than language/type system features/power. If it were otherwise we'd have seen a huge uptick by now wrt adoption rates for the compile-to-js languages. Maybe that will change in future but for now the big players drive the javascript bus...
- spion 10y agoTS->JS is very different from both in that the resulting JS code is the same as the typescript code with the types removed. In contrast Haskell and Scala compile to entirely different (and mostly unreadable) code
- sixbrx 10y agoOne thing you might miss in TS is the ability to just try to check or cast an object at run-time to check that it's really of some nominal type, or structurally compatible with some type/interface. TS can't do that because it doesn't have runtime type information for its types - the types are a compile-time only thing. TS does allow creating functions that return type predicates, but that requires your own manual checking as implementation, the type system can't help you write those as far as I know. I was missing this mostly for incoming requests. A good solution for me has been to generate json-schema from typescript interface definitions, using the typescript-json-schema npm package. Then incoming data can be checked vs the generated json schemas. Works fine and I get json schemas for api endpoints from it as well, so no complaints.
- jtmarmon 10y agoahh interesting, that seems like a pretty significant difference. just to clarify, this means that you wouldn't be able to do things like: if (my_var instance_of MyCustomType) in TS, but you could in normal statically typed languages, correct?
- sixbrx 10y agoI shouldn't have included nominal typing - it seems the instanceof operator actually works, e.g. see http://stackoverflow.com/questions/24705631/typescript-myobject-instanceof#24707830 http://stackoverflow.com/questions/24705631/typescript-myobj.... But in TS itself structural typing is used everywhere for actual type checking (except for classes with private members), and from my understanding there's no way to have TS help you check at runtime whether a type is structurally compatible with a value.
- WorldMaker 10y agoIt's a bit more complicated than that because of JS's prototype-oriented object system. If MyCustomType is a proper prototype (say you built it with the class keyword) you can certainly instanceof it. (That said there are strange edge cases where statically typed class-based object intuition falls down against prototype-oriented reality.) The issues tend to start cropping up as you get further into TS-specific types like generic types. In a statically typed language you can inquire about the specifics of an implementation of a generic directly, and often even dispatch directly on that type. JS has no concept of your generic wrapper type and you need some other flag or logic to determine the runtime type of your generic code.
- spion 10y agoHaskell and Scala are safer than TypeScript... but not by too much :) The only major safety feature lacking in TypeScript are variance annotations and proper variance for functions, which are bivariant WRT their arguments. Short demonstration of the problem: // this should not be assignable, functions should be // contravariant WRT arguments, so if o2 is subtype of o1 // then F1 is subtype of F2, which means you can't assign // a value of type F2 to F1: there are functions in the // set of functions F2 that don't belong in the subset F1 type O1 = { a: string; b: string } type O2 = { a: string; b: string; c: string } type F1 = (o: O1) => string type F2 = (o: O2) => string // should not compile! let f: F1 = (o: O2) => { return o.c.toString() } f({a: '1', b: '2'}) // throws at run time (o.c undefined) Other than that, TypeScript has been pretty safe since the addition of "strictNullChecks". Haskell and Scala have algebraic datatypes (or case classes) which make it easier to model data (especially in Haskell where the syntax is really nice). TypeScript also supports disjoint unions (union of several types with a tag field that has a concrete string value as the type) and control flow analysis, so with some effort it can provide "idiomatic" JS-style ADTs. Haskell and Scala can do exhaustiveness checks, making sure you've covered all the cases. TS can also sort of do that (when strictNullChecks are on): type T1 = { tag: 't1', value: string } type T2 = { tag: 't2', value: number } type T3 = { tag: 't3' } type T = T1 | T2 | T3 function f(t: T):string { switch (t.tag) { case 't1': return t.value; case 't2': return t.value.toString() // Compiles only if you uncomment this line. // Otherwise inferred return type string|undefined is // incompatible with specified return type string //case 't3': return 'N/A' } } Not as pleasant or as general as Haskell, but better than most other mainstream languages. Both Haskell and Scala have higher kinded generics, something that TypeScript still lacks. This means importing category theory concepts in TypeScript is pretty much impossible. The problem isn't just with category theory though; the need to parameterise generic types with other generic types as type arguments can come up everyday JS code too. For example, a library that accepts a promise constructor as an argument is parameterized by a generic type [1] Before v2.1 TypeScript already had some powerful features for working with record types, such as record unions and intersections. With mapped types introduced in 2.1 however, you could say it surpasses Haskell and Scala in this regard - if not with features, then at least with pleasantness / ease of use. I believe its possible to achieve the same things in Haskell with vinyl [2][3], but those are definitely not Haskell's native records. Not sure if Scala's shapeless [4] can provide something similar (the answer is probably yes). Haskell has type classes, and Scala can provide the "equivalent" via implicits+traits. Both of these allow a very nice and generic style of programming with implementation flexibility (you can write new typeclass instances for old code). TypeScript has structural interfaces, which offer some flexibility compared to nominal interfaces: you can write an interface that is a subset of old code, then use both old and new code under that interface without modifying the old code. Still, its not as flexible as typeclasses (the implementation must already be a subset of the original old code). They also can't offer the return-type-based implementation selection that typeclasses can. Of course, Haskell and Scala both have various type / macro / template superpowers that TypeScript doesn't have and isn't likely to ever have. For everyday programming though, the above list should cover the vast majority of interesting features. [1]: https://github.com/Microsoft/TypeScript/issues/1213 https://github.com/Microsoft/TypeScript/issues/1213 [2]: https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vinyl-Tutorial-Overview.html https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vi... [3]: https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vinyl-Core.html#v:-60--60--42--62--62- https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vi... [4]: https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#extensible-records https://github.com/milessabin/shapeless/wiki/Feature-overvie...