在 Typescript 3.8+ 上声明类型后导出类型

Export a type after its declaration on Typescript 3.8+

在使用 Typescript 3.8+ 声明类型后尝试导出类型时:

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

... VS Code 给出以下错误:

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

所以我按照错误提示做了:

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

然而,这导致了另一个错误,由 eslint 发出:

Parsing error: Declaration or statement expected.

2 个问题:

  1. 为什么被认为是“再出口”?
  2. 在打开 --isolatedModuls 标志的 Typescript 3.8+ 上是否允许这种导出,as explained here

我设法解决了我的问题:

  1. --isolatedModuls 标志打开时,VS Code's TypeScript language service 无法判断我们尝试导出的类型是否源自当前模块。

    有一个类似的Babel Github issue,这里是这样解释的:

    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?
    

    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. 如错误所提示的那样,确实是这样:

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

    如我的问题所述,这导致了 eslint 发出的错误,但该错误实际上是错误的。我无法消除该错误,最终重新创建了我的 Typescript 应用程序,该应用程序成功了。
    所以对于未来的读者,请确保您遵循正确的安装:

    // 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 
    

    至于eslint,Typescript的eslint模块,叫做@typescript-eslint,按照上面的步骤应该安装在node_modules下。您可以通过 decalring 一个未使用的变量来验证:

    const a = 1;
    

    这会导致@typescript-eslint发出警告:

    'a' is assigned a value but is never used

    P.S.

    请注意,一些错误仍然由 eslint 本身发出,而不是由 @typescript-eslint 发出。例如,尝试错误导出我们上面声明的变量a,像这样:

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

    ... 你会得到前面提到的 eslint 发出的解析错误。