Repository navigation
Abandon TypeScript? #541
Description
Because of the modular nature of this library. I'm starting to feel like maybe TypeScript isn't a natural fit for what we're doing.
Why TypeScript to begin with?
If we were to support TypeScript typings, it made sense to "transpile down". There have been other benefits to the project over type as well, but the main thing was for the automatic generation of typings information for our partners on the Angular team, and for the larger community of TypeScript developers that care about high-quality typings information. The idea was that be using TypeScript, it would generate the best .d.ts files for us.
Issues
Frequently we're forced to jump through hoops just to generate proper .d.ts files. For example: We have to add property "stubs" for methods on Observable we wanted to be optional for modularity's sake. That actually causes other issues where we need to monkey with the prototype of ScalarObservable if we want to override those methods, because TypeScript can't handle reconciling non-existent instance properties that could contain functions and prototype "methods", when there's no real distinction in JavaScript between a "method" on a prototype, and a property key on a prototype that has a function in it.
The goal was to have operators that end users could simply import into their own Observable and decorate the prototype thereof. Basically what we're doing in our Rx.ts file, only specific for their own output purposes. Even better, they could just use ES7 function bind. TypeScript makes the former unergonomic and the latter completely impossible (because it doesn't support function bind).
We also have way too many cases where we're forced to cast as <any> in our app just to make things work that should "just work" in JavaScript. I suppose in a lot of cases, we could use an Interface instead, but it's generally not something that is going to help the public API so it's probably not worth doing anything but the <any> cast. Still, each time we're force to do that what we're really doing is working-around TypeScript.
The good of TypeScript
TypeScript has helped us find and avoid bugs. I've seen it. Places were we were passing the wrong type to the wrong place, etc.
TypeScript makes it really unergonomic to create polymorphic functions. This is a very good thing, IMO, because polymorphic functions should be avoided for performance reasons, and for the reasonability of the functions that you're writing.
Having type information in our code to statically analyze will provide us with opportunities to do smarter things with our minification processes in the future this is something I know our friends at Angular are working on (per @jeffbcross). It may also provide some ability to do more granular "tree-shaking" at some point.
Alternatives
- Babel/ES6 port our generated ES6 code over to be our
srcand maintain .d.ts files by hand. This might actually be less work than dealing with TypeScript because we'll only be typing the type information for the operators one time, and we only really have to maintain it for what is our public API. - ES5 plain, old, ES5 with CJS. Their are a lot of sucky things about this approach. One is that if we wanted to support ES6 modules, we would need to do some sort of transpile in what I would normally consider to be "the opposite direction". We'd also be missing a lot of really nice features.
Thoughts?
The timeline for this would be totally indeterminate; However, I'd want to make the move prior to release if we made a move at all.
Activity
benlesh commentedon Oct 15, 2015
Also, I'll admit that #468 was, at least in part, stemming from the fact that there is some ugliness around our modular operator structure in TypeScript.
staltz commentedon Oct 15, 2015
I actually think it was a good idea to build it with TypeScript. For the performance argument (avoiding polymorphism) and for the reliability argument (Dynamic typing is really not a sane idea for large codebases, a lot of smart developers advocate types for large projects).
If you just want to get stuff done and get types out of your way, then there isn't anything better than dynamically typed JavaScript. That's the main benefit of dynamic typing: getting out of the developer's way. Types are there to guide the programmer. We shouldn't default to putting
<any>whenever "TypeScript complains". Instead we need to stop and actually think what possible types that thing can assume. The benefit will be greater in the long run, and that's what this project is for.Either way, we'll have to maintain things by hand, be that
.d.tsor property stubs in Rx.ts. And I'd say now is quite late to migrate to ES6.Definitely not this option. This library targets the future, not the past.
staltz commentedon Oct 15, 2015
PS:
ES7 function bind is a Stage 0 feature, we shouldn't make any assumption on its availability.
benlesh commentedon Oct 15, 2015
SHUT YOUR STINKIN' MOUTH @staltz! (I love that feature) 😛
staltz commentedon Oct 15, 2015
mattpodwysocki commentedon Oct 15, 2015
Yeah, I kept away from TypeScript just because it kept the number of contributions lower in terms of contributions because the barrier to entry was a bit higher. But to each their own...
RyanCavanaugh commentedon Oct 15, 2015
We're looking at this and want to make sure we understand the scenarios before making any recommendations.
My initial take on this is that you should be using declaration merging to add things to the
Observabletype as they "become available" via imports (but more on that later).This is the same link as before (intended?) so I don't quite have context on what this means
TypeScript doesn't distinguish these two cases, which I would think would make things easier rather than harder.
Several questions here -- "their own Observable" means a subclass of Observable? Or is the intent that end users should be modifying
Observable.prototypefrom user code ("decorate" === mutate, or decorator?).Just thinking concretely, in your ideal modular world, user code would look something like this?
Possibly the big missing piece here is the ability augment global types from within a module.
benlesh commentedon Oct 15, 2015
@RyanCavanaugh ... oops. I meant this link
Yes, that's part of the original design. Mostly to support dialects that don't have ES7 function bind.
Not really. In my ideal world it looks like this:
... but unfortunately, we have needs in the non-transpiled world too, in which prototype decoration is what we're stuck with. :\
benlesh commentedon Oct 15, 2015
@RyanCavanaugh .... One big, near-term issue for the Angular team around Rx, is: How do they include the operators people will need without bloating their byte-count? This is one of the reasons the modular design exists.
So, in a world where we need type information for those methods for TypeScript users, I need to export a .d.ts file that shows all possible core operators on Observable if they're there.
Right now I'm just defaulting to adding all "core" operators as stubs to Observable.
RyanCavanaugh commentedon Oct 15, 2015
What does the ideal world, absent the ES7 bind operator, look like?
benlesh commentedon Oct 15, 2015
@RyanCavanaugh I think I'd like it if the TypeScript compiler didn't complain that I'm adding prototype methods to a subclass when the superclass's instance properties of the same name are undefined. Alternatively, I'd love it if there was a way to tack on type information in the .d.ts for properties that may or may not be there.
RyanCavanaugh commentedon Oct 15, 2015
Either I'm misunderstanding the scenario, or that's already supported:
https://github.com/RyanCavanaugh/TryRx/blob/master/sample.ts
https://github.com/RyanCavanaugh/TryRx/blob/master/augmentations.d.ts
The one piece that would make the whole story work 100% smoothly is if importing a module could cause side effects to types in the global namespace. In that setup, using the example above, you'd have e.g. a module
eventhat had a type-system side effect of augmenting the global typeObservableThat's not currently alowed, but it's something we've discussed.benlesh commentedon Oct 15, 2015
I guess, I'm too new to this... is
augmentations.d.tssome idiomatic way of altering the type information? How does the type system know to pick that up?RyanCavanaugh commentedon Oct 15, 2015
The filename there is arbitrary - any file you add to your compilation that declares the same interface or namespace in the same scope adds to that type rather than declaring a new one. You'd still need to
/// <referenceit or otherwise add it to the set of files the compiler sees.10 remaining items
RyanCavanaugh commentedon Jan 20, 2016
Granted I'm biased, but I honestly find the notion that having type annotations on code raises the barrier to entry to be completely baffling.
If I see this method signature (from the actual code, with type annotations removed):
I just have no idea what's going on. Is
nexta callback? How many parameters does it take? Is 'error' the result of some other thing that wasthrown? I have to assumecompleteis a boolean, based on no other cues. I would guess that all parameters are required. What members doesnexthave? What members doesthishave? Who calls this function? Is it intended to be public, or private?When I see this:
Oh. Now I know that
nextis a void-returning callback that I should invoke with the containing type's type parameter.erroris optional, and it's a function that I should invoke with an error object.completeis also optional, but doesn't take any parameters. If I'm not sure whatTis, I can Go To Definition to see where it's defined. If I try to pass an incorrect value tonext, I'll get an error that tells me what I messed up.The hard part about coming to a new codebase is figuring out what the heck is going on. Types drastically simplify that navigation, and serve as a reliable computer-verifiable mechanism for programmers to communicate the semantics of a component.
As Vonnegut wrote, "any scientist who couldn't explain to an eight-year-old what he was doing was a charlatan". If someone can't write a type annotation to indicate the intent of their code for the next programmer to come along, they shouldn't be writing that code in the first place.
bholloway commentedon Jan 21, 2016
There are a few reactive libraries and frameworks out there. I don't think I would have looked here if not for Angular 2.0.
So long as they retain a commitment to this library I think you gota go with whatever they're pushing, and last I heard that's TypeScript.
I'm not up to speed with TypeScript and cannot really contribute right now either. Sometimes I have to stare at the code a little longer than normal to understand it.
I never got on the CoffeeScript train either. But if Angular 2.0 is "best with Typescript" then myself and a boat load of other people are going to start learning it on that basis alone.
benlesh commentedon Jan 23, 2016
I love the folks on the Angular team, but I would never, ever choose a programming language based on this. TypeScript was chosen for a few reasons:
Number 4 there is key. If it weren't a superset or ES6, would have never used it.
It's just ES6 (aka ES2015). with some extra stuff after a colon.
TypeScript:
ES6:
TypeScript:
ES6:
Other than that, there's generics for typing purposes, which exist in many other languages (e.g.
Foo<T>). And there areinterfaces, which are just contracts you expect some object to adhere to. It's really not that different from ES6 at all.It can be more typing for sure (heh, pun). But editors like Visual Studio Code, WebStorm, or even Sublime or Atom (with some plugins) make working with TypeScript fantastic when it comes to code completion and refactoring.
scharf commentedon Feb 24, 2016
@BerkeleyTrue I think there is a huge difference between CoffeeScript and TypeScript: CoffeeScript tries to change the syntax of JavaScript little additional benefit. You can essentially automatically convert CoffeeScript -> JavaScript -> CoffeeScript.
TypeScript on the other hand, adds a lot of information that help tools (IDEs) and humans to improve the correctness of code. It is a superset of JavaScript and that makes it so attractive.
BerkeleyTrue commentedon Feb 24, 2016
@scharf My point was not TypeScript === CoffeeScript. It's that adding an extra layer to this project will reduce the number of developers contributing to this repo. Not everyone who does JavaScript will be able to contribute here because they are not using TypeScript.
jeffbcross commentedon Feb 25, 2016
@Blesh whatever yes you would.
On Wed, Feb 24, 2016 at 3:59 PM Berkeley Martinez notifications@github.com
wrote:
experimenti commentedon Mar 1, 2016
Please support if possible... Angular 2 + TypeScript + RxJS is an excellent combo.
ssmartin commentedon Mar 22, 2016
+1 for Typescript.
The fact that supports "Clean code" standards (code readability) and type checking (at compile time) are definitely a huge plus from my point of view.
ericwooley commentedon Mar 23, 2016
I don't contribute to RxJS, but this came up on top of google when I was searching, so I wanted to throw my two cents in on this conversation and suggest discussing flow.
I use typescript and flow for two similar projects, and I find that flow has all the benefits (sans it being a little slower to check types) with a lot less headache, because it s still javascript, and it's not trying to be anything else.
I am an outsider, so feel free to disregard, I won't be offended.
LongLiveCHIEF commentedon Apr 26, 2016
For anyone who has mentioned barrier to entry... the pain is real. Many people coming onto reactive programming are struggling to learn these new concepts, while at the same time having to grapple with learning how to use babel in order to follow the instructions, and then again having to learn typescript to find out if the problems they're experiencing are bugs in rxjs5, or just problems with how they're trying to implement things.
Using Typescript is just the straw that broke the camel's back, IMHO. I've got team members right now trying to get up to speed with all of the below, at the same time:
let,=>,::)Now toss in the additional syntax and et al... that TypeScript is introducing... and you're basically killing any momentum these developers could hope to make.
Why would these devs just be learning this stuff now?
For developers who aren't freelancers, or belong to small companies or app factory shops, the "upgrade barometer" for when they need to learn something, at least in the js world, is native support in node.js.
Many of the es6 features are only now becoming standard in node v4, v5. Many of the features rxjs5 depends on to get up and running easily, require a ton of polyfilling. With the uphill battle of learning all the rest of this stuff at the same time, just groking the polyfilling implications is a barrier to entry.
By using TypeScript, you're not really giving users the option... they have two choices:
If you would use just plain old es6/es2015, I think you'd allow for one option that is at least on pace with the 99% of the js community that doesn't involve a barrier to entry they haven't already accepted as a sunk cost.
benlesh commentedon Apr 26, 2016
@LongLiveCHIEF you don't have to use TypeScript to use RxJS 5. Not at all. This entire thread was about using TypeScript to build RxJS 5. You could use plain old ES5 JavaScript, ES6, TypeScript, CoffeeScript, ClojureScript, PureScript, basically anything you want to consume RxJS 5... just so long as it's either JavaScript or it compiles to JavaScript.
There aren't any features that RxJS 5 "depends" on that require polyfilling.
LongLiveCHIEF commentedon Apr 26, 2016
I know you don't have to use TS to use RxJS 5, and assuming you have your tcs system/tooling all set up, it's very easy to follow the examples set forth by the test specs, to help figure things out that reading the docs might not have helped with.
If you haven't yet taken the TS leap though, and you're trying out the RxJS concepts to determine if you want to use it in a distributable module, which is a common use case for many, then trying to get RxJS 5 to run using natively supported syntax for node v5, is a bit difficult to figure out.
case in point... I can't even tell if I'm doing something wrong here, or if I'm running into a bug.... but something that would have taken me 3 minutes 6 months ago (rx, commonjs style requires), has had me scratching my head for hours now.... and either way, I know it's something stupidly simple that just seems to be eluding me.
I can't help but feel that if the same files I reference in that post were written in .js, I would be able to figure out what I was doing wrong without asking embarrassing questions on SO, or having to take half a day to make sure I fully understand TS and the implications of es6 module that I had all wrong thanks to leaning on how babel v5 used to handle consuming them from
require.slavovojacek commentedon Oct 10, 2016
+1 for sticking with TypeScript.
Today we are having JavaScript do everything. Soon someone will come up with a JavaScript framework to replicate an operating system. I don't personally think that the language is advanced enough (at least not yet) to support such pressure.
TypeScript has been instrumental in reducing a specific subclass of bugs and while it is not TypeScript itself that helps reduce business logic bugs (henceforth application bugs), I do believe it makes working with projects running JavaScript more productive. It's very expressive and makes you and/or your team focus on what matters – application logic.
PS If one's aim is to reduce application bugs, one shall practice TDD.
lock commentedon Jun 6, 2018
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.