-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typescript/Flow: Inconsistent union and intersection type multiline formatting #3986
Comments
We should probably use the same logic to print both variants, then just swap in the |
Seems pretty straight forward to fix. I'll try to make a PR during the weekend |
For reference: The current behavior is desired. See #3988 (review) |
The proposed behavior is growing on me. I see the argument about type bar = foo & {
baz: number
} but that could also be special cased. |
It would be nice to special-case it for |
the case i deal with fairly often is the intersection of functions. here's a small example: declare var fn: ((aaaaaaaaaaa: "a") => string) &
((bbbbbbbbbbbb: "b") => number) &
((ccccccccccccc: "c") => boolean);
(fn("a"): string);
// Expected error, because when passing 'b' it's expected to return a number
(fn("b"): string);
// same type with unions
declare var fn2:
| ((aaaaaaaaaaa: "a") => string)
| ((bbbbbbbbbbbb: "b") => number)
| ((ccccccccccccc: "c") => boolean);
// Won't work the same way, all of them are errors
(fn2("a"): string);
(fn2("b"): string); it would be nice to have them formatted similar to unions |
i didn't realize the original issue was for typescript. but i guess it's still relevant for flow as well :) |
This is still a problem, IMO. E.g. the following code constructs a type, which includes properties from type type Foo<A> = Pick<A, Exclude<keyof A, 'baz' | keyof Bar>> & Bar & { baz: string }; The intersection expression has three members: // Print width: 60.
type Foo<A> =
Pick<A, Exclude<keyof A, 'baz' | keyof Bar>> &
{ baz: string } &
Bar; But Prettier wraps it in pretty unreadable and non-sematic manner: // Print width: 60.
type Foo<A> = Pick<
A,
Exclude<keyof A, 'baz' | keyof Bar>
> & { baz: string } & Bar;
// ↑ What the hell is this? How can I be able to read it? FYI: Prettier wraps non-type expressions in desired manner: // RHS expression is almost identical to the RHS expression from above:
const Foo = Pick(A, Exclude(keyof(A), 'baz' | keyof(Bar))) & { baz: string } & Bar; becomes // Print width: 60.
const Foo =
Pick(A, Exclude(keyof(A), 'baz' | keyof(Bar))) &
{ baz: string } &
Bar; Also, I agree with @albertorestifo that formatting with leading |
What I wrote: type IO =
& (
| { type: "in"; opts: InputOpts }
| { type: "out"; opts: OutputOpts }
)
& (
| { mode: "file"; file: string }
| { mode: "buffer" | "stdio"; stream: PassThrough }
) What came out: type IO = (
| { type: "in"; opts: InputOpts }
| { type: "out"; opts: OutputOpts }) &
(
| { mode: "file"; file: string }
| { mode: "buffer" | "stdio"; stream: PassThrough }) :/ Also I just noticed that with |
@thorn0 milestone3? as & and | are also logical operators |
@tommarien we can fix it without milestone 3 |
@evilebottnawi i just saw a ressemblance with the logical javascript operators, that is why i suggested the same milestone ;) |
I'd argue this should be extended to all operators for consistency, or at least be made configurable, because current situation is incredibly inconsistent, especially if you decide to format TypeScript one way, and JavaScript the other way. What I mean is this: const x = string1
+ string2
+ string3
const y = possiblyFalsyExpr1
|| possiblyFalsyExpr2
|| null |
Hi everyone, I don't really understand why #3988 has not been accepted, and what is intentional by having the current formatting behavior. The arguments put forwards are:
For the 1st one, lot of people would like but can't as we mostly use prettier for our syntax formatting, and who's doesn't use tools for formatting are probably not a good example to follow 😅 For the 2nd one, it is the same issue with the pipe So, can we debates on this and close this issue ? Thanks |
I can't help but think that it would be a lot simpler maintenance-wise to just treat intersections the same as unions. Currently intersections have their own unique logic so can't easily be standardised to format the same as binary expressions - they're going to need their own, custom logic in order to look good - which will increase the maintenance burden over time as more edge cases are found (and introduced by new syntax). Example of bad formatting just for intersections: #14726, #14773. If we instead formatted multiline intersections the same as unions - with a leading I wonder if it's time to revisit this change with the looming v3 major release? As an aside - it's worth noting that this sort of thing doesn't impact flow that much now-a-days because the vast, vast majority of flow object types are merged via spreads |
Just set up prettier in a large-scale project, and this was definitely a bizarre issue to run into. I would love to see this revisited. The inconsistency between intersection and union has definitely been a hit in readability for our team. Also, my biggest frustration with it is we have a number of intersections that we regularly add to, and not being able to just copy the last item down and edit it is pretty annoying Also, as mentioned above, the primary case that seems to be used to justify the inconsistency (shown below) seems easy enough to special case, and probably should be special-cased for both intersections and unions. It certainly doesn't feel like there is enough benefit to warrant the inconsistency, and it seems to be less readable in almost anything besides the below use case type bar = foo & {
baz: number
} |
Prettier 1.10.2
Playground link
Input:
Output:
Expected behavior:
I think the Interections type should use the same format as the one used for the Union type.
The text was updated successfully, but these errors were encountered: