React/Typescript /VScode - 导入路径不能以“.tsx”扩展名结尾

Mus*_*ett 11 typescript reactjs babeljs visual-studio-code

我有一系列已转换为打字稿的反应项目。其中一些使用 webpack,而其中一些只使用 babel,因为它们是其他(webpack)项目/实际应用程序使用的库。

除了在一个非 webpack 项目中,我收到错误“导入路径不能以 .tsx 扩展名结尾”,例如在

import LoadingLogo from '../ui/LoadingLogo.tsx';

Run Code Online (Sandbox Code Playgroud)

我可以通过省略扩展名或使用 // @ts-ignore 来解决这个问题,但这些都不是最佳解决方案,因为该项目在重构时将是 jsx 和 tsx 的混合,我想成为能够一目了然地看到导入中使用的文件类型。

我将项目转换为打字稿的步骤是

  1. 安装打字稿
  2. 安装@babel/preset-typescript
  3. 添加
presets: [ @babel/preset-typescript ]
Run Code Online (Sandbox Code Playgroud)

到我的 babel.config.js

更令人困惑的是,在其他(非 webpack)应用程序之一中,我运行了相同的 babel 设置,但我没有看到这个问题。有什么明显的我遗漏了吗?作为参考,我在有问题的项目中的 babel.config 看起来像这样

module.exports = function(api) {
  api.cache(true);

  return {
    ignore: ['node_modules/**/*'],
    presets: [
      ['@babel/preset-typescript'],
      [
        '@babel/preset-env',
        {
          loose: true,
          targets: {
            node: 'current'
          }
        }
      ],
      '@babel/preset-react'
    ],
    env: {
      translations: {
        plugins: [
          'syntax-async-functions',
          '@babel/plugin-syntax-dynamic-import',
          'dynamic-import-node',
          [
            'react-intl',
            {
              messagesDir: './messages',
              enforceDescriptions: false
            }
          ]
        ]
      },
      production: {
        plugins: [
          'jsx-strip-ext',
          [
            'babel-plugin-styled-components',
            {
              ssr: true
            }
          ],
          'syntax-async-functions',
          '@babel/plugin-syntax-dynamic-import',
          'dynamic-import-node'
        ]
      },
      development: {
        plugins: [
          [
            'babel-plugin-styled-components',
            {
              ssr: true
            }
          ],
          'syntax-async-functions',
          '@babel/plugin-syntax-dynamic-import',
          'dynamic-import-node'
        ]
      }
    },
    plugins: [
      '@babel/plugin-transform-runtime',
      '@babel/plugin-syntax-dynamic-import',
      '@babel/plugin-syntax-import-meta',
      '@babel/plugin-proposal-class-properties',
      '@babel/plugin-proposal-json-strings',
      '@babel/plugin-transform-classes'
    ]
  };
};
Run Code Online (Sandbox Code Playgroud)

我在非 webpack 项目中的 babel 配置没有问题,看起来像这样

module.exports = function(api) {
  api.cache(true);

  return {
    presets: ['@babel/preset-typescript'],
    ignore: ['node_modules/**/*'],
    extends: 'myProject/babel.config.js',
    env: {
      production: {
        plugins: [
          [
            'module-resolver',
            {
              alias: {
                '^myProject/src/(.+)': 'myProject/lib/\\1'
              },
              extensions: ['.js', '.jsx'],
              stripExtensions: ['.js', '.jsx']
            }
          ],
          [
            'babel-plugin-styled-components',
            {
              ssr: true
            }
          ],
          'syntax-async-functions',
          '@babel/plugin-syntax-dynamic-import',
          'dynamic-import-node'
        ]
      },
      development: {
        plugins: [
          [
            'babel-plugin-styled-components',
            {
              ssr: true
            }
          ],
          'syntax-async-functions',
          '@babel/plugin-syntax-dynamic-import',
          'dynamic-import-node'
        ]
      }
    }
  };
};

Run Code Online (Sandbox Code Playgroud)

两个项目的 tsconfig.json 看起来像这样

{
  "compilerOptions": {
    "module": "esnext",
    "outDir": "dist/",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true,
    "target": "ESNext",
    "allowJs": true,
    "checkJs": false,
    "jsx": "react",
    "pretty": true,
    "skipLibCheck": true,
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "lib": ["dom", "dom.iterable", "ESNext"],
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}
Run Code Online (Sandbox Code Playgroud)

我的第一直觉是查看模块解析器插件,但这似乎没有任何区别。有什么明显的我遗漏了吗?

fru*_*oaf 16

我将文件从 navMenus.tsx 重命名为 navMenus.ts 并更改了导入它的方式:

import { navMenus } from "../../views/navMenus.tsx";
Run Code Online (Sandbox Code Playgroud)

import { navMenus } from "../../views/navMenus";
Run Code Online (Sandbox Code Playgroud)

这解决了问题


Mat*_*abe 12

我很遗憾地说,我怀疑你是否能够按照你想要的方式解决这个问题。TypeScript(特别是 TSC)不允许 ts/tsx 文件的显式扩展名...它与导入中的隐式文件扩展名以及 ts/tsx 文件如何编译为 js/jsx 文件有关。世界可能对此并不高兴,但它似乎就是这样。

你可以使用// @ts-ignore,但我认为你会失去智能感知

更新:我从下面的评论中注意到一些 TypeScript 工具确实允许扩展。显然 Deno 需要它们,尽管我没有与 Deno 合作过。TSC 编译器不允许它们。

  • 某些 TypeScript 工具允许显式扩展,而其他工具则不允许。说 TypeScript 禁止它们是不准确的。在 Deno 中,它们是强制性的。在许多其他运行时,它们是可选的。在 VS Code 的 linter 中,根本不允许使用它们。 (2认同)
  • 很高兴知道。我将据此更新我的答案。应该注意的是,我所说的禁止扩展并不是 VSCode,而是 TSC。 (2认同)

小智 5

为了解决您的问题,您需要:

  1. 确保project.json中有一个包含代码的tsconfig.json文件
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}
Run Code Online (Sandbox Code Playgroud)
  1. 使用代码检查或创建一个react-app-env.in.ts文件

/// <reference types="react-scripts" />

正是这个react-app-env.d.ts 文件解释了 TypeScript 如何使用 ts、tsx 等文件扩展名

在此输入图像描述

  1. 删除导入中的 tsx 文件扩展名。还要删除 TypeScript 会咒骂的所有扩展

比如之前:

import { Header } from "./Header.tsx";

删除扩展后应该是这种情况:

import { Header } from "./Header";

  1. 如果您在进行这些更改时正在运行一个项目,请将其停止并重新启动。由于这些更改仅在编译阶段启动项目时应用