Comments (70)
I just shipped 1.4 with official TypeScript support https://github.com/prettier/prettier/releases/tag/1.4.0 !
Thanks everyone who helped out and beta tested it. I'm going to close this issue now. If you see anything weird, please create a new issue and we'll look into it :)
from prettier.
@kamek-pf yes! If everything goes right, next week you'll be able to use prettier for typescript files :)
from prettier.
@ChristopherBiscardi mentioned that he was interested in working on it, so here are some thoughts around it.
Word of warning
Before going into the details on how to implement it, I want to call out that the way prettier works is by printing the entire code from scratch from the ast. As a consequence, you can't really have a "done is better than perfect" attitude and instead you need to get very close to 100% coverage until people can actually start using it.
The worst thing that can happen is that someone runs prettier to reformat its code and it generates code that does not behave the same way, which is unfortunately very easy to do when printing JavaScript from the ast.
The problem
The reason why prettier is able to support Flow is that the flow parser outputs JavaScript ast using the "estree" specification and on-top of that adds a few flow-specific nodes. So supporting flow is just a matter of supporting the flow extensions. Same for JSX.
Unfortunately, for TypeScript, they decided to reimplement their own AST format that doesn't follow the estree specification. So, to support it we need to reimplement the printing code for everything, not just the typescript extensions.
TypeScript -> ESTree
The first solution that can get you started the fastest and the best long term solution is to convert the typescript ast into estree + typescript-specific nodes. There is already a project that does it: https://github.com/eslint/typescript-eslint-parser
With this setup, you just have to add a new parser ( https://github.com/prettier/prettier/blob/master/src/parser.js ) and add support for TypeScript-specific nodes.
This big downside with this approach is that adding a compatibility layer is usually a complex endeavor and the conversion code is going to be pretty complex and therefore contain more bugs that are harder to fix.
But, if it works out, we're in a really good shape:
- we can support js, jsx, typescript and flow in the same codebase
- the typescript -> estree project will be really solid and we can all the js ecosystem tools like eslint, jscodeshift, babel-transforms, rollup will be able to work with typescript with minimal changes.
prettier natively understands typescript
This approach is likely going to be a fork of prettier. The idea is to take src/printer.js and for each ast node then modify the code to the typescript equivalent.
The performance is going to be better since you don't have to go through a translation layer and the code should be easier to understand as it just deals with typescript ast. However, this is likely not a good idea to refactor the code to support both ast at once, so this means that you are going to hard-fork prettier.
How to make sure it works
There are multiple things you want to do:
- There is an option
--debug-check
in current prettier that ensures thatprettyprint(prettyprint(x)) === prettyprint(x)
which is a really good heuristic to make sure that you correctly print something. This is going to be your best friend when working on it. - You want to run all the existing tests that do not have flow ast nodes and make sure that
prettyprint(estree) === prettyprint(typescript)
- You want to add all the typescript tests ( https://github.com/Microsoft/TypeScript/tree/master/tests/cases ) to prettier snapshot tests and make sure they all print correct code.
The great thing with prettier is that it's very easy to get a sense of progress and to know if you are correct or not. Also, while the number of edge cases is very large, it is finite. So there's a light at the end of the tunnel.
Once you have all this, you should be good to go, good luck :)
from prettier.
I started enums and then went on vacation for two weeks 😂 . I'm back now though and picking it up again.
from prettier.
TS team would be tempted to run the prettier on their codebase
Challenge accepted!
from prettier.
@avindra I'm working with the TS team directly on this, rest assured :)
from prettier.
@Ciantic I'm curious, why are you saying that it needs to interact with the TypeScript server? In order to pretty print code we just need to get an AST, which ts parser + ts to estree project gives us.
As for "likely to be implemented". I'm a maintainer of prettier and I'm fully supportive of adding typescript support. Since prettier already prints all the standard JavaScript + JSX + Flow, it's only a small amount of work to add support to typescript.
from prettier.
I think it's not reasonable to expect Prettier to do TypeScript formatting. It would be much more likely to be implemented in codebases such as @basarat's https://github.com/alm-tools/alm
Re-emitting the whole code from AST requires to interact with TS server so intricately.
from prettier.
I just published [email protected] to npm if people are interested in trying it out. I'll do a proper release tomorrow :)
from prettier.
I have implemented a bunch of more types at https://github.com/pajn/prettier that I hope to PR soon but before that I need to land initial TS support in ast-types as well benjamn/ast-types#213
I think @ChristopherBiscardi started on enum support as well which is quite a big piece as it currently does not exist at all in prettier (as neither JS or Flow supprots that). Another big piece that's missing is all modules syntax that I don't know of any work on that yet. Yet another is parsing .ts files without jsx support to enable old style casts and type parameters on arrow functions.
And then theres probably small things all over the place. For those I think that the best strategy is still to just pull tests from TS and fix whatever comes up.
from prettier.
@kamek-pf ohh, I had no idea. Well, if the TS team is interesting in using prettier instead of what they currently have, I'd love to help :)
from prettier.
You can see some examples of their AST here: https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#traversing-the-ast-with-a-little-linter
I also reached out to the TS team again about adding support to Babylon. Gonna talk about it with them sometime soon.
from prettier.
A Babylon fork that supported TypeScript would actually be a huge boon to the TypeScript community. It means not only could there be interop with this package, but also Eslint and many other JavaScript meta tools. Anyone who added support to Babylon for TypeScript would make be making a really big community impact.
from prettier.
Thanks @vjeux, I am going to improve the docs for typescript-eslint-parser
. It is definitely ready for something like this
from prettier.
Playing with this now, so far so good...
from prettier.
It seems that #1306 (and https://github.com/prettier/prettier/tree/master/tests/typescript/conformance/types) is where most of the effort is at right now...
from prettier.
The typescript ast looks completely different than babylon and flow :(
http://astexplorer.net/#/gist/e3f144f9a0465d41bcb98c4fdaae22a7/71a9e0879487952414d7f9a7d892f6849ddd03c5
from prettier.
Adding TypeScript support to Babylon is feasible. The TypeScript team just said previously they didn't have the bandwidth for it right away.
from prettier.
As Prettier will get support for parsing and emitting both TS and Flow, such a transpiler could be implemented as an AST converter in the discussed plugin support to Prettier. That would save you from having to emit valid code from the AST.
from prettier.
@maxime1992 did you add to your package.json:
"scripts": {
"prettier": "prettier --parser typescript --single-quote --trailing-comma --write \"./**/*.ts\""
}
Then yarn run prettier
?
from prettier.
Ok, cool, thanks!
I was actually hacking out a bit more than I originally thought, and so there are more broken specs than my comment above suggests.
However, we are still not that far off. I will hopefully put together a PR for this at the beginning of next week.
Currently laid up with a bad back injury so cannot spend very long on my laptop at a time.
from prettier.
@crohlfs if you can find which files are causing issues and try to come up with a small repro case, that would be awesome. Then create an issue in this repo with the problems :)
from prettier.
This only applies to the javascript subset of Typescript, though. You'd lose all type related nodes and the output would no longer be semantically the same as the input.
When doing the translation, you need to introduce a whole new set of node types that represent the type syntax, just like Flow does. It's still a potential solution because at least we'd get the JS subset for free, but it would also be a lot slower.
from prettier.
It's actually looking like integrating TS support will be pretty nice. typescript-eslint-parser
does a great job of translating the AST and with very small changes in prettier JamesHenry was able to parse all the current JS tests with the Typescript parser in PR #915
For TS specific syntax, I have an initial PR open that start that work #1033, again the changes are small and it's mostly just wiring up TS specific nodes to already existing code.
Typescript do have a lot of strange syntax but most of it is small and contained and do not effect the formatting very much. It will of course require some work and take a few iterations to become usable in real projects but it can absolutely be done and maintained.
from prettier.
if you run prettier through a npm/yarn script you need to add an extra double dash before the args
yarn run prettier -- --parser typescript --single-quote --trailing-comma --write "./**/*.ts"
but you don't need yarn to run prettier
prettier --parser typescript --single-quote --trailing-comma --write "./**/*.ts"
is enough
from prettier.
It was something the Babel & TypeScript teams discussed early on but they decided to go with their own implementation. My guess is adding TypeScript support to Babylon is not realistically feasible. Maybe @ahejlsberg can point us in the right direction?
Also, @thejameskyle I remember seeing you discuss with some members of the TypeScript team on twitter about this subject, do you remember who you were talking to?
from prettier.
@Pajn a start would probably be getting all of the TypeScript fixtures to parse: https://github.com/Microsoft/TypeScript/tree/master/tests/cases
from prettier.
As far as I can tell (never used prettier before so take with a pinch of salt), the state of things when using a parser based on typescript-eslint-parser
is:
(Based on adding "tests/flow"
to testPathIgnorePatterns
in jest config)
Snapshot Summary
› 7 snapshot tests failed in 5 test suites. Inspect your code changes or run with `npm test -- -u` to update them.
Test Suites: 6 failed, 67 passed, 73 total
Tests: 7 failed, 210 passed, 217 total
Snapshots: 7 failed, 210 passed, 217 total
Time: 13.191s
Ran all test suites.
error Command failed with exit code 1.
...so not all that far away.
There is one major point to consider. TypeScript fundamentally has more syntax than JavaScript (ESTree) and flowtype.
In typescript-eslint-parser
, we capture these extra syntax nodes using the naming convention TS${ORIGINAL_TSNODE_NAME}
.
I would imagine we could fairly simply add logic to the parser to ignore nodes which match this naming convention, I will see how far that gets us...
(This may also surface cases where we fall back to TSNodes where we shouldn't, so should be interesting either way)
from prettier.
This is super exciting! Thanks for plugging it in. It looks like we're going to be able to go that way without too much work then!
For the TS node, we'll want to write custom printer for them. But, we don't need to do them all at once. What we've done to bootstrap prettier is for nodes we didn't supported, we would just return the original one.
It's super easy to do, you can see how we do it for // prettier-ignore
: https://github.com/prettier/prettier/blob/master/src/printer.js#L74
from prettier.
Would you mind opening a PR with your work in progress so that I can play around with it?
from prettier.
@JamesHenry Great work!
Is there some place where I could help?
from prettier.
For typescript nodes, I've been playing with adding them in this switch in typescript-eslint-parser, which is responsible for converting ts.SyntaxKind
AST types into the ESTree types. Specifically, my current attempt is to get the following to parse (and then print) as an example of a pure typescript syntax (enum
) which can be used to inform further kind conversions.
declare enum E1 {
y = 4.23
}
// Ambient enum with computer member
declare enum E2 {
x = 'foo'.length
}
from prettier.
Perhaps we could gather a group of interested folks together to help on this feature?
from prettier.
I am wondering how compatible the two codebases would be. Because with TypeScript you can use the TypeScript compiler and language service for parsing/emitting.
Optimally it would be nice to not fracture the two, so I am curious to see what ideas others have as to which approach to take.
from prettier.
Would a new parser even be necessary? So people could write interface X {}
in JS code. It would be up to the runtime or other build tooling to error on these cases.
from prettier.
Typescript could realize use a formatter like this. TSLint is great and even has some plugins to do formatting for you, but it suffers the same pitfalls as ESLint outlined here.
from prettier.
This project relies heavily on the AST Format babylon generates. TypeScript has a completely different AST format that isn't compatible. My guess is that you'd need to reimplement everything using a similar approach.
from prettier.
Anyone with insight in Babylon that know how viable it would be to add Typescript support to it, instead of using the TS parser?
I expect that the Flow support should be a helpful start.
from prettier.
It seems plausible to re-implement the translation into prettifier's intermediate command representation on top of the typescript AST. I might try it tonight and see how painful it'd be.
It'd suck to maintain going forward, though.
from prettier.
@AndyMoreland If you are trying to convert the TypeScript AST to a Babylon AST you're gonna have a bad time, they do things entirely different. Also you'd be creating an invalid Babylon AST.
from prettier.
I have some experience converting Typescript AST to Babylon's and it's not that bad - most of the nodes just map directly between the two. This only applies to the javascript subset of Typescript, though. You'd lose all type related nodes and the output would no longer be semantically the same as the input.
from prettier.
Just now reading through this, as I was going to file an issue for TypeScript support.
I'm not familiar with TypeScript, but I feared that they had their own AST format. I am completely open to supporting TypeScript and willing to mentor anyone who wants to help out with that, but it sounds like we need a parser that generates a babylon/estree/mozilla-compatible AST with additional nodes representing the type syntax. I don't think we can realistically do anything until we have that.
from prettier.
As Typescript isn't too far from flow syntactically I don't believe that forking the flow plugin to a ts version is that hard for the parser itself. Good test coverage is harder though as it's just much more code.
I forked babylon and copied the flow plugin and fixtures (removing just one which utilized {| |}
which is Flow-specific syntax (causing an unknown token error) into Typescript versions as a start.
https://github.com/Pajn/babylon
I don't know if starting from Flows fixtures is a good idea, does anyone have a better alternative?
from prettier.
This might be helpful as well (TS -> ESTree AST): https://github.com/eslint/typescript-eslint-parser
from prettier.
Didn't see your question until I had written that, yes will open it up as soon as I can
from prettier.
This is awesome :) I didn't expect so much progress so quickly. I'm diving into the respective codebases today so I can be useful as this progresses. Looking forward to playing with the PR.
from prettier.
Awesome news. Thank you for your work. @ALL
from prettier.
@Pajn It looks like @JamesHenry landed his PR for typescript-eslint-parser
support and @ChristopherBiscardi wanted to start adding support for TS nodes soon (see here #915 (comment)).
from prettier.
Yeah, I read that but thought I should continue here as new PRs will likely reference this issue :)
It's that I don't really know where go go from there. I guess, start copying tests from Typescript and make sure they work but I don't really know where to begin or how. For example, is this an okey start:76e26f0...Pajn:master
I copied some tests from Typescript, made a small change (add the any key to the printer) to avoid crashes. Now there are some TS specific stuff stripped from the output, should I precede fixing that?
from prettier.
Currently the parser assumes jsx: true
when using typescript, this breaks old-style typecasts like these:
let x = <[]>[];
jsx must be toggled per file-ending .ts
or .tsx
.
Currently this feels pretty low-prio which is why I add it as a comment here instead of opening a new issue, but I still wanted to have it written down somewhere.
from prettier.
Good point @Pajn, that kind of conditional wasn't necessary for my first PR because it was just dealing with existing JS and JSX tests.
from prettier.
I'm all for it if can be done and maintained.
I suppose my fear is that with so much unique syntax TypeScript has (and more keep coming) that formatting all of that in opinionated exact manner is maintenance problem.
It would be best at least if TypeScript specific formatting rules could be maintained in the language server itself, and maybe use prettier for ES parts, not sure how feasible that is. Anyhow this would require TypeScript team to implement formatting rules in their codebase, and I'm not sure do they see formatting as such time saver as many here do.
P.S. I think the litmus test is can it be done so well that TS team would be tempted to run the prettier on their codebase?
from prettier.
A great reason for having TS in prettier is #1041. Printing everything in a nice way is hard, there a so many cases to think about and prettier has already done that a lot, #1041 is aimed at Flow but will benefit TypeScript just as much :)
from prettier.
a question a little bit offtopic:
Do the ASTs for FlowType and TypeScript contain the types as explicit node information?
I was thinking about writing a transpiler for those two languages and if the type information is contained in the syntax trees this should be doable with not too much effort.
from prettier.
@kaoDev
That depends on what you mean.
The AST contain all information that the source code does contain but in a more easy-to-work-with format. So all type annotations etc. is there. However, the scope is not resolved and no types as been flown. That means that there is no easy way to see that a is a number in var a = 5
but you can see that b is a string in var b: string
. However the type information is very dumb, it's just the textual representation of the type annotation so there is no easy way to see that c and d have the same type in
type A = string
var c: A
var d: string
and you can only guess that e and f have the same type in (it could be two types with the same name that somehow shadows each other)
var e: A
var f: A
If you want full type information you must work with the TypeScript Language Server and the equivalent for Flow.
from prettier.
for a first try this dumb information should be enough, a complete intelligent transpiling will be very hard with all the types/interfaces coming from external libraries and external typedefinitions, but with this it should be possible to transpile pure FlowType code to pure TypeScript code.
from prettier.
What still needs to be done to complete this? I saw the WIP PR but I'd love to hope get TS support in.
from prettier.
There are still a few typescript-eslint-parser PRs (which add AST nodes in babel) for TypeScript to land.
from prettier.
I can offer this insight. If your JavaScript parser is already supporting JSX then it is capable of supporting both TypeScript and TSX. The biggest hurdle is knowing when to support a JSX like XML tag versus TypeScript's type generics. The syntax is very similar, so don't look to syntax for help. The difference is more a matter of context. Generic types occur in different places in the grammar than do JSX tags, aside from a known edge case. Internally generic types have very different syntax rules compared to XML, as well.
The only collision, overlap, in context between JSX code and generic types is following a return
keyword. This is a feature unique to TypeScript since it has generic types in the fashion of Java or C# but follows the grammar of JavaScript. To solve for this edge case I recommend creating an option to preference JSX by default or TypeScript when true.
That and a bunch of test samples, which you can find from Github search, is all you need to quickly nail this problem.
from prettier.
Just FYI: some folks at Microsoft have started on adding Typescript support to Babylon
from prettier.
You guys can copy/paste my solution: https://github.com/prettydiff/prettydiff/blob/master/lib/jspretty.js#L2166-L2216
Somethings to keep in mind:
- I am not sure about TypeScript but Java and C# but support an empty type tag called a diamond
<>
- Type generics can be nested:
HashMap<String, ArrayList<String>>
example is from Java. I know the syntax is different in TypeScript, but I made an attempt to support all cases in my approach - The most important thing to realize in making this work is that the generic types exist in different contexts than JSX tags and that they are internally parsed a bit different
These conventions aren't really that complex, so it isn't worth stressing over or over-engineering. Just test your approach against a lot code samples for durability.
from prettier.
@JamesHenry interesting, does this mean we can expect built in support in some future version of TS ?
from prettier.
@vjeux well that's awesome ! I was referring to the TS language server though.
It's already capable of formatting blocks of code or entire files, but the output is simply not as good as what Prettier is able to do.
from prettier.
There's actually a package that seems to work with it https://github.com/vvakame/typescript-formatter
from prettier.
Just ran it on my project, caused quite a few errors. What would be the best way of raising the issues? A fork with failing tests?
from prettier.
Hi ! Now that there's a beta, I'd like to give a try on my code base (angular project with typescript).
I installed it like that :
yarn add --dev [email protected]
And used it like that :
yarn run prettier --parser typescript --single-quote --trailing-comma --write "./**/*.ts"
(also tried to run it on only one file)
Output :
error Command failed with exit code 1.
What am I missing here ?
Thanks
from prettier.
Thx guys, I think I'm just tired, don't know why I didn't think about that earlier ... ! 😅
It's working well <3 !
from prettier.
Weird behavior ! I thought it was working but in fact, it's only taking the files into the first level of the repositories :
{
...
"scripts": {
"prettier:base": "yarn run prettier -- --parser typescript --single-quote --trailing-comma es5",
"prettier:check": "yarn run prettier:base -- -l \"./**/*.ts\"",
"prettier:write": "yarn run prettier:base -- --write \"./**/*.ts\"",
"precommit": "lint-staged"
},
...
}
It seems that (yarn ?) is interpreting the path before it's passed to prettier. But I'm not sure what's going on here.
Any idea ? :)
from prettier.
Cool stuff, thanks to all involved who've been working on TS support! I ran it on my TS codebases without any problems.
@ others , mind keeping this issue on-topic by not discussing yarn run
issues? ;)
from prettier.
@vjeux 😱
from prettier.
Related Issues (20)
- Add support for `#graphql` comment for formatting GraphQL HOT 3
- Non-idempotent formatting of Angular templates (new lines being inserted on each run) HOT 1
- yaml with folded multiline string and "--prose-wrap always" improperly wraps (and is not idempotent) HOT 3
- documentation request: yaml and prose-wrap
- Enforce consistent use of file extensions in import statements HOT 1
- Unstable formatting of javascript method chains HOT 1
- Dependencies required by scripts/build/utils.js are not reflected in package.json HOT 1
- Give us the option to only apply a plugin on a file HOT 1
- Prettier breaks vue2 syntax when using filters in template
- [MDX] Does not keep indentation in multiline strings HOT 1
- Issue when running prettier for any APEX class in my project HOT 1
- Range formatting doesn't work
- VSCode prettier extension and the `prettier --write .` giving two different results HOT 2
- In less file, automatically insert space between ) and ` HOT 2
- prettier leaves "prettier-ignore" statements in code HOT 3
- CLI: Exit code is 0 when --check is specified and "no parser could be inferred" (since version 3.1)
- Ignore CDATA in HTML or option to ignore it HOT 3
- Prettier adding trailing comma after implicit returns and after last param in function call in vue 2 projects HOT 2
- Add an option to optinaly disable changes introduced in 2.3.0 HOT 2
- JS multi-line comments are not formatted when there are spaces between lines that are created with `*` HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from prettier.