compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Astro transform fails on several forms of multiline exports

Open duanwilliam opened this issue 3 years ago • 9 comments
trafficstars

What version of astro are you using?

1.1.5

Are you using an SSR adapter? If so, which one?

None

What package manager are you using?

pnpm

What operating system are you using?

WSL2

Describe the Bug

(don't know if this should go in the compiler repo)

(Seems similar to the recently submitted withastro/compiler#536, but found independently and (I think) more accurate on reproduction / diagnosing the cause.)

Astro fails at parsing certain forms of multiline exports (not sure exactly why), some of which are not uncommon patterns.

For context, I encountered this bug when trying to define a Props interface for a component, that extended a subset of some other defined type:

export interface Props extends Pick<
    OtherType,
        | 'key1'
        | 'etc'
> {
    // ...
}

where I would consistently get an error message of

Transform failed with 1 error: [path/lineno/position]: ERROR: Expected ">" but found "$$[filename excluding extension]"

This error occurs not just for interfaces or generic types, but also for basic and union types if not on the same line as the export keyword (with slightly different expected/found in the error message):

export type Foo =
    'string'
export type UnionType =
    | 'foo'
    | 'bar'

It's not restricted to types, either:

export const foo =
    'foo'
export const noop =
    () => {}

Notably, these issues only occur relating to some part of the expression going to a new line, and only when the expression in question is being exported: if the export keyword is removed, the transform no longer fails. This can be seen in the minimal reproduction example.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-hmtihg-ej7ccx?file=src/pages/index.astro

Participation

  • [ ] I am willing to submit a pull request for this issue.

duanwilliam avatar Sep 04 '22 04:09 duanwilliam

Additional case reported on StackOverflow, which provides a CodeSandbox reproduction.

Works

---
import { SomeType } from 'package';

export type Props = SomeType & {
  margin?: number | string
};
---

Doesn’t work

---
import { SomeType } from 'package';

export type Props = {
  margin?: number | string
} & SomeType;
---

Throws an error:

Transform failed with 1 error: ERROR: Unexpected "&"

delucis avatar Nov 28 '22 10:11 delucis

I see this issue marked as p2-has-workaround. What is this workaround? I looked for making Astro LSP ignore one particular line, but haven't found anything of use. Is there a way other than turning off LSP before write?

TymekDev avatar Jan 22 '23 10:01 TymekDev

Just a note to anyone visiting this issue that exporting Props is not needed (and never has been) unless you're actually using it in other files.

I'll bump the prio back to a p3 because people hit it often and formatting can trigger this automatically

Princesseuh avatar Jun 29 '23 13:06 Princesseuh

Prettier formats code with this syntax, and it works fine in Next.js (haven't tried in other projects), so why is this failing, here?

Are unions like

type Foo =
 | string
 | number;

still valid TS (the documentation page no longer show this format).

yanickrochon avatar Sep 30 '23 05:09 yanickrochon

Prettier formats code with this syntax, and it works fine in Next.js (haven't tried in other projects), so why is this failing, here?

Are unions like

type Foo =
 | string
 | number;

still valid TS (the documentation page no longer show this format).

Yes, this is valid TS. It's a bug in our compiler, only affects exported things though

Princesseuh avatar Sep 30 '23 07:09 Princesseuh

I was able to work around this by defining the type separately from the function:

type StaticPathResult = () => Promise<
  { params: { year: number }; props: Props }[]
>;

export const getStaticPaths: StaticPathResult = async () => {
  // ...
}

xavdid avatar Oct 12 '23 02:10 xavdid

In my case it was prettier auto formatting forcing me into this issue.

My current workaround is to transform this:

type Test =
  | 'this'
  | 'test':

to this:

// prettier-ignore
type Test = 'this' | 'test'

fratzinger avatar Dec 20 '23 12:12 fratzinger

Just hit this issue for the first time. I can confirm that altering the line breaks somewhat combined with a // prettier-ignore solves the issue.

gersomvg avatar Jun 28 '24 14:06 gersomvg