microsoft/TypeScript

Babel plugin for typescript

zerkalica opened this issue ยท 22 comments

Just an idea: do you think about babel plugin for typescript? Babel has a powerfull plugin api and many plugins. tsc api is weak and has no usable plugins at current moment.

You are reimplementing many features in monolithic tsc, such as own ast specification, jsx, babel-plugin-module-resolver instead of reusing existing.

Look at babel plugin collection: https://www.npmjs.com/search?q=babel-plugin It 's will be good to reuse them and give developers to create own.

Babel has already pluginnable support for flow syntax, why not to do same thing for typescript?

Typescript specification, checker, ide integration is best, but drop typescript compiler and move to babel.
Give an possibility to babel/flow community easily migrate to typescript.

PS: I try to search same question in issues, but not found it.

Relevant HN thread.

Babel has already pluginnable support for flow syntax, why not to do same thing for typescript?

Actually the following is the entire source code of the babel flow syntax plugin:

export default function () {
  return {
    manipulateOptions(opts, parserOpts) {
      parserOpts.plugins.push("flow");
    }
  };
}

The actual logic for parsing flow annotations is all built in to babel's core. This 'plugin', like other babel syntax plugins, just tell the core to use a builtin feature. So at least for source code parsing, babel is also monolithic.

Ok, syntax is monolithic. But in babel I can create some transformations about Reflect.defineMetadata. In typescript - i can't, built-in typescript reflection generator is weak for me. No typeof, generics, functions, jsx support, dictionary arguments, etc.

Some example:

function ComponentD(rec: { p: number }, deps: {a: A}) {
    return <div>AA</div>;
}
Reflect.defineMetadata('design:subtype', 'jsx', ComponentD);
Reflect.defineMetadata('design:paramtypes', [{a: A}], ComponentD);

function fn(a: A, b: Class<B>, f: ResultOf<factory>) {
    function fn2(a: A) {}
}
Reflect.defineMetadata('design:subtype', 'func', fn);
Reflect.defineMetadata('design:paramtypes', [A, B, factory], fn);

More examples

#6508 covers a "plugin" architecture for TypeScript. Now that TypeScript has moved to a transformation emitter in 2.1, it makes plugins a viable concept and the early work to explore how that might be accomplished is on the roadmap for TypeScript 2.1.

Considering TypeScript is already heading this direction, it almost negates this request, in my opinion.

Typescript specification, checker, ide integration is best, but drop typescript compiler and move to babel.
Give an possibility to babel/flow community easily migrate to typescript.

@zerkalica for what it is worth, I appreciate the spirit of the remarks about us all getting together. Philosophically, normatively perhaps we should, but there are a few things I would like to point out.

  1. A lot of the things you like about TypeScript, for example IDE integration and type checking, are driven by the compiler. For example, Babel has had support for Object Rest/Spread for a long time now, but the TypeScript team took more time implementing the feature so that it could be correctly typed and thusly correctly checked, and thereby highly toolable.

  2. I think TypeScript is more committed to long term stability.

  3. I think one of the best things for the JavaScript world was the rapid enthusiastic every growing adoption of both Babel and TypeScript side by side. This helps ECMAScript itself evolve faster, and more wisely because new features are now not only being vetted in terms of implamentability in browsers, they are vetted in terms of usability by two independent communities.

  4. Babel and TypeScript also provide each other and the community with valuable reference points. For example, Aurelia lists under technical benefits the following bullet point about Code Quality

    Code correctness is independently verified by two transpilers: Babel and TypeScript.

    It might seem like just marketing, but when you are writing a framework targeting hypothetical languages that may never exist, this is actually a rather nice thing to be able to say.

  5. The thing that sticks out in this equation is Flow. It is not clear if it is a Facebook project for Facebook and by Facebook but simply made available for the larger community or if it is actually something that is intended for wide external adoption. Also, while I have nothing against it personally, it does not mesh particularly well with the JavaScript world. For example flow only just recently became available to windows users, while JavaScript has become a universal cross platform language. Flow is not dog-fooded as Flow is implemented in OCaml, not Flow checked JavaScript. This also means I cannot simply import Flow into my module and call it like I can with TypeScript (browser and node)

https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-flow-strip-types/src/index.js is also instructive

As you can tell by the source code, the Babel parser understands Flow syntax, not TypeScript syntax, then they strip it out later. It's pretty baked in (see https://github.com/babel/babylon/blob/master/src/index.js#L14 )

@thejameskyle would a PR to Babylon be accepted if someone implemented this?

@RyanCavanaugh It's long been desired, do you want to talk about it with the team sometime?

@aluanhaddad

A lot of the things you like about TypeScript, for example IDE integration and type checking, are driven by the compiler.

It's strange for me, why compiler do type checking and ide integration? Why not separation concern tools for checking, compiling, ide integration, unix way, etc.

TypeScript team took more time implementing the feature so that it could be correctly typed and thusly correctly checked, and thereby highly toolable.

This feature can be divided on two separate features: transpiling and checking. In first, give to programmers posibility to write some new feature and in second give them tool for checking. We can see it in babel/flow. I think, summary, time of implementing this feature in babel and flow is not less than typescript.

This helps ECMAScript itself evolve faster, and more wisely because new features are now not only being vetted in terms of implamentability in browsers, they are vetted in terms of usability by two independent communities.

Yes, but ECMAScript can evolve even more faster, if two communities can interchange their features.
Say, in babel i can generate custom reflection metadata for functions via plugin, but in typescript i can't do that. I saw issue about transformations-emitter #5595, but it probably would be your own specification of plugin and ast api. I need to reimplement my existing babel-plugin in typescript with same functionality.

I talking about common specifications for ast and transform plugins.

Code correctness is independently verified by two transpilers: Babel and TypeScript.

It's verified in Babel, but not in Flow. Typescript not comparable with babel itself, only with flow+babel, because typescript do type checking, babel - not.

And it's es2015 without good typescript features, like implement, constructor shortlands and etc.
In world, where we have c# and java, latest babel or typescript features still looks poor, and they downshifts to es2015. Javascripts standarts evolves very slowly and some features needed just now.

For example flow only just recently became available to windows users, while JavaScript has become a universal cross platform language. Flow is not dog-fooded as Flow is implemented in OCaml, not Flow checked JavaScript.

It's some technical aspects. Many compilers written on different languages (php, python). I don't know why flow developers choose OCaml. Probably, OCaml is better than js for writing ast parsers and good for fast start. Flow parser can be compiled to js via js-of-ocaml, but Flow checker whole depends on C library: multi-process stuff, fs, etc. Hypothetically they can be compiled to asm.js. I believe, flow checking in browser is the nearest feature.

It's some technical aspects. Many compilers written on different languages (php, python). I don't know why flow developers choose OCaml. Probably, OCaml is better than js for writing ast parsers and good for fast start. Flow parser can be compiled to js via js-of-ocaml, but Flow checker whole depends on C library: multi-process stuff, fs, etc. Hypothetically they can be compiled to asm.js. I believe, flow checking in browser is the nearest feature.

My point here is that because TypeScript is written in TypeScript the design and day to day use of the language are inherently connected in a way which is beneficial. It is a self validating process. Additionally, because TypeScript is written in TypeScript is written in JavaScript, the ability to host it in its target environment comes for free. You cloud compile Flow via js-of-ocaml + asm.js but that is a complex process that is not a concern for TypeScript.

It's verified in Babel, but not in Flow. Typescript not comparable with babel itself, only with flow+babel, because typescript do type checking, babel - not.

My point was that it is a good thing to have diversity in the JavaScript transpiler ecosystem.

It's strange for me, why compiler do type checking and ide integration? Why not separation concern tools for checking, compiling, ide integration, unix way, etc.

I think they are fairly decoupled. I generally use my IDE to code, view errors, and refactor, etc. I use a loader or bundler to transpile the source. These tools use the compiler as a component of a larger pipeline.

And it's es2015 without good typescript features, like implement, constructor shortlands and etc.
In world, where we have c# and java, latest babel or typescript features still looks poor, and they downshifts to es2015. Javascripts standarts evolves very slowly and some features needed just now.

Java has evolved at a snail's pace. C# has evolved rapidly while retaining integrity. JavaScript has evolved slowly in the past but the pace is increasing.

Appreciate the good discussion here but it's probably best to debate monolithic vs micro-architecture elsewhere. Feel free to log a new issue to continue the discussion and we can tag it Discussion.

@zerkalica I raised an issue on the Babel issue tracker: babel/babel#5201

@yortus looks like they are looking to start adding TypeScript to babylon babel/babylon#320

alloy commented

@andy-ms Seems like this can be closed nowadays with babel 7 being able to transform TS?

I think so. ๐Ÿ‘

Docs are still pending. @DanielRosenwasser is working on that.

I for one am very excited about this. We've hit couple of dead ends in TS JS hybrid project by trying to use tsc as the transpiler. Hover I just realized the reverse is possible. I.e using babel as the transpiler for both js and ts and only using Typescript for IDE support and type checking as part of tests.

Thank you for making this possible. Look forward to the docs.

We've hit couple of dead ends in TS JS hybrid project by trying to use tsc as the transpiler.

would love to hear more about these blockers.

@mhegazy In my Node.js project, I need custom path resolving so I write config instead of ../../../config. TSC actually provide custom path resolving but let them in place in the output. Path still config thus triggering not found module error.

I'm now stuck with an awful and non-scalable chain of compilation where TSC just compile TS specific business and Babel transpile and enhance so I'm looking forward for the babel integration.

Can you convert between TSC ast and babel ast typescript?

alloy commented

@goodmind Not out of the box, youโ€™ll have to write your own code to do so.

@goodmind Or you could just use babylon's own TypeScript parser in the first place.

@andy-ms I mean convert between babylon AST format and TypeScript Compiler AST (this repo) itself

The only way to convert from the babylon AST to TypeScript's AST would be to render it and parse again.