TS4023:导出变量<x>具有或正在使用外部模块的名称<y>,但不能被命名。

55

我之前看到过这个问题的答案,但它们似乎没有涉及到这个特定的用例(或者它们不起作用/没有帮助)


我之前见过类似的回答,但它们好像没有涵盖这个具体的使用场景(或者它们无法解决/没有帮助)。
import {Route} from 'vue-router';


export const detailRoute = {
  path: '/detail/:id',
  component: Detail,
  props: (route: Route) => ({
    state: route.query.state
  })
};

detailRoute使用了Route,我正在导入它,但我猜作为一个命名导入{Route}似乎不起作用?有没有一种不同/更好的方法可以实现这个目标?我也尝试过export {Route};,但没有帮助。

tsconfig.json:

    {
      "compilerOptions": {
        "target": "ES2017",
        "module": "ES2015",
        "moduleResolution": "Node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "forceConsistentCasingInFileNames": true,
        "allowSyntheticDefaultImports": true,
        "noEmitHelpers": true,
        "importHelpers": true,
        "pretty": true,
        "alwaysStrict": true,
        "declaration": true,
        "declarationDir": "./types",
        "lib": [
          "DOM",
          "ES2017",
          "DOM.Iterable",
          "ScriptHost"
        ],
        "baseUrl": "./client",
        "paths": {
          "styles/*": ["./app/core/styles/*"],
          "core/*": ["./app/core/*"],
          "components/*": ["./app/components/*"],
          "containers/*": ["./app/containers/*"],
          "assets/*": ["./assets/*"],
          "config/*": ["./config/*"]
        }
      }
    }

精确错误:

TS4023: 导出的变量 'detailRoute' 具有或正在使用外部模块“/Users/chris/<projectname>/node_modules/vue-router/types/router”中的名称 'Route',但无法命名。


1
请查看GitHub上的此解决方案:https://github.com/Microsoft/TypeScript/issues/5711 - James
谢谢,那就是我开始的地方,但似乎没有帮助,或者我漏了什么。我导入了{Route},尝试导出{Route},我不知道还能做什么来表达“Route在这里”。 - user358089
我无法重现你的问题。我正在使用TypeScript 2.3和commonjs模块。你在用什么? - Shaun Luttin
ES6模块与Node解析,以及声明= true; - user358089
9个回答

38

编译器未能确定detailRoute的确切形状,因为它不知道Route的形状。

选项1

解决这个问题的一种方法是从其源导入Route,从而提供编译器需要确定detailRoute形状的信息。

import { Route } from "./../node_modules/vue-router/types/router";

export const detailRoute = {
  props: (route: Route) => null,
};

由于您在问题中导入的vue-routerindex.d.ts文件重新导出了Route,因此它没有提供编译器所需的Route直接引用。

选项2

另一个选择是完全将detailRoute从静态类型中移除。

import { Route } from 'vue-router'; // index.d.ts

export const detailRoute: any = {
  props: (route: Route) => null,
};

由于 any 选择了取消静态类型,编译器不需要弄清楚 detailRoute 的形状。

选项 3

另一个选项是您在自己的答案中所做的。由于您提供了类型注释,编译器再次不需要弄清楚 detailRoute 的形状。

import { Route, RouteConfig } from 'vue-router'; // index.d.ts

export const detailRoute: RouteConfig = {
  props: (route: Route) => null,
};

另请参见

https://github.com/Microsoft/TypeScript/issues/5711

尝试输出[模块]时,编译器需要编写一个对象类型字面量...表示模块的形状。但是,范围内没有直接引用[Route]的名称,因此该类型“无法命名”,并且会出现错误。

如果您添加[Route]的[直接]导入,错误应该会消失。


16

这个问题是因为我试图构建一个库,做如下操作:

interface Props {...};
const MyComponent = ({...}:Props)=>{<>...</>}

我改为:

type Props = {...};

问题已解决。


3
这很奇怪,但是它确实为我解决了问题。 - fregante
1
了解为什么它修复了问题会很有趣。 - souki
这对我也解决了问题,但肯定很奇怪。 - baseten
你也可以将其更改为导出接口Props {...}; 但仍然奇怪的是TypeScript能够使用类型,但不能使用接口。 - Thomas
那为什么类型可以工作,而接口却不行呢?我以为它们是可以互换的。晚编辑:这可能与dynamic()本身的类型有关。请参考这个答案 - Paul Razvan Berg

9
显然,这是我的问题的解决方案:
  import {Route, RouteConfig} from 'vue-router';


  export const detailRoute: RouteConfig = {
    path: '/detail/:id',
    component: Detail,
    props: (route: Route) => ({
      state: route.query.state
    })
  };

指定detailRoute是一个RouteConfig(它使用Route),问题得到了解决。我可能误解了它应该如何工作,但这样修复了它。


5

当我编写一个rootReducer时,我遇到了这个问题,如果有其他人也在做同样的事情,请注意以下内容。我导入了由其他未导出类型(状态、操作)组成的类型化reducer。

简短回答:从reducer中导出所有的操作状态类型!

当组合类型的部分未被导出并且需要依靠类型推理时,似乎容易出现问题。在这种情况下,我们需要推导rootReducer的类型(如果你有不止几个reducer,则显式地编写其类型会太麻烦)。

const rootReducer = combineReducers({ typedReducerA, typedReducerB, ... }

1
我也遇到了reducer的问题,对我来说解决方案是在尝试扩展RootState之前从中删除唯一符号。我的解决方案是:Subtract<RootState, CombinedState<{}>>Subtract来自于utility-types npm包。 - smac89

3

以下是针对此问题的扩展答案,供寻找答案的人参考。

满足以下条件:

Typescript

已安装版本:^4.8.3

TSConfig
{
  "module": "NodeNext",
  "moduleResolution": "NodeNext"
}
package.json
{
  "type": "module"
}
布局
src/lib/types.ts      // contains all type defs
src/lib/something.ts  // contains type def consumption and error

我在自己的库中遇到了这个问题。
代码:
1. 使用了导出类型(Box) 2. 导出的类型使用了未导出的类型(Dimension) 3. 通过隐式类型(没有显式的: SomeType注释)来使用导出类型 4. 错误提示说Box是[命名但不能被] -(读作:“我找不到某个东西的名称”)
原因:
Typescript正在寻找被称为Dimension的Box类型,但失败了。“无法命名”是一个不清楚的错误,但基本上意味着“嘿,我不知道这个东西里面有什么”。
我的解决方案:
导出嵌套类型。
export interface Box {
  width: Dimension;
}

interface Dimension {
  size: number;
  meta: any;
}

Should become

export interface Box {
  width: Dimension;
}

// Update this:
//     interface Dimension {
// To this:
export interface Dimension {
  size: number;
  meta: any;
}

2
似乎是由于具有本地类型定义所引起的。
type ABC = {abc: number};
export const function = (): ABC => { return {abc: 123}};

将类型定义移动到单独的文件中并导入它们。
//types.ts
export type ABC = {abc: number};

//function.ts
import {ABC} from "./types";
export const function = (): ABC => { return {abc: 123}};

同样的事情,但使用枚举。将其移到一个单独的文件有所帮助。 - undefined

1
正如其他人已经指出的那样,这确实是由于引用本地导入的类型所导致的。
没有这个commit
- type JsonObject = {
+ export type JsonObject = {

我的应用程序开始出现错误,无法正常运行。
Error: @contra/utilities:build: src/Logger.ts(3,14): error TS4023: Exported variable 'Logger' has or is using name 'JsonObject' from external module "/home/github/actions-runner/_work/gaia/gaia/node_modules/.pnpm/roarr@7.18.0/node_modules/roarr/dist/types" but cannot be named.
Error: @contra/utilities:build: src/Logger.ts(3,14): error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

导出JsonObject使错误消失。
非常奇怪的是,如果你看一下错误的起源JsonObject然后引用JsonValue,这也没有公开导出。但与JsonObject不同的是,这没有引起任何问题。
type JsonValue =
  | JsonObject
  | JsonValue[]
  | boolean
  | number
  | string
  | readonly JsonValue[]
  | null
  | undefined;

/**
 * @public
 */
export type JsonObject = {
  [k: string]: JsonValue;
};

感觉像是中的一个错误或者是一个文档不完善的行为。
如果您是错误来源包的作者,解决方案是导出导致错误的类型。

-2

对我来说,添加一个返回类型解决了问题

export const test_setUpApp = async (args?: {
    fixtureData: SomeType;
}) => {
    ....
    }

报错了,提示:SomeType。问题已解决:

export const test_setUpApp = async (args?: {
    fixtureData: SomeType;
}):Promise<ReturnType> => {
    ....
    }



-2

只需将以下内容添加到tsconfig.json中即可:

compilerOptions: {
  ...
  "declaration": false,
  "emitDeclarationOnly": false
}


2
这可能需要一点解释。 - ChrisCrossCrash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接