OfirD
OfirD

Reputation: 10461

Export a type after its declaration on Typescript 3.8+

When trying to export a type after its declaration with Typescript 3.8+:

type Type = { Prop: string };
export { Type }

... VS Code gives the following error:

Re-exporting a type when the --isolatedModuls flag is provided requires using export type

So I did as the error suggests:

type Type = { Prop: string };
export type { Type }

However, that caused another error, emitted by eslint:

Parsing error: Declaration or statement expected.

2 questions:

  1. Why is it considered "re-exporting"?
  2. Isn't this kind of export allowed on Typescript 3.8+, with --isolatedModuls flag on, as explained here?

Upvotes: 1

Views: 1938

Answers (1)

OfirD
OfirD

Reputation: 10461

I managed to solve my problem:

  1. When the --isolatedModuls flag is on, VS Code's TypeScript language service can't tell if the type we're trying to export originated in the current module or not.

    There is a similar Babel Github issue, where it is explained:

    In order to determine whether something is a type, we need information about other modules.

    import { T } from "./other-module";
    export { T }; // Is this a type export?
    

    There's also a great elaborated explanation on this Reddit thread:

    type space is TypeScript's domain: all of the types that make up your app. They only exist at compile time. Once the compiler is done, the resulting JavaScript has no types left in it. Value space is basically the opposite: it's the stuff that sticks around and survives into the JS.

    type Foo = { bar: string };
    const a: Foo = { bar: 'hello' };
    

    Here, Foo is in the type space, everything else is in the value space.

    The problem with isolatedModules, is they can't know which space they are working with, since each file is compiled individually. So if you do:

    export { Foo } from './bar';
    

    in a file, TypeScript can't know if Foo is in the type space (if it is, it just gets thrown away as it won't be in the resulting JavaScript), or if it is in the value space (ie it's JS, so it needs to be included in the resulting output).

  2. As the error suggests, the way to do it is indeed:

    type Type = { Prop: string };
    export type { Type }
    

    As described in my question, that caused an error emitted by eslint, but that error was actually wrong. I couldn't get that error go away, and eventually recreated my Typescript app, which succeeded.
    So for future readers, make sure you follow the correct installation:

    // the following creates a typescript app, and installs required type declarations, 
    // which are: @types/node @types/react @types/react-dom @types/jest
    npx create-react-app hello-world --template typescript
    
    // you'd probably work with react-redux, so install it as follows:
    cd hello-world
    npm install --save redux @types/redux
    npm install --save react-redux @types/react-redux 
    

    As for eslint, the eslint module for Typescript, which is called @typescript-eslint, should be installed under node_modules after following the above steps. You can verify that by decalring an unused variable:

    const a = 1;
    

    Which would cause @typescript-eslint to emit a warning:

    'a' is assigned a value but is never used

    P.S.

    Note that some errors are still emited by eslint itself, and not by @typescript-eslint. For example, try to incorrectly export the variable a we declared above, like so:

    const a = 1;
    export a; // gives an error
    

    ... and you'll get the aforementioned Parsing Error emitted by eslint.

Upvotes: 2

Related Questions