76

I've seen this answered before, but they don't seem to cover this specific use case (or they don't work/help)

import {Route} from 'vue-router';


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

detailRoute uses Route, which I am importing, but I guess as a named import {Route} it doesn't work? Is there a different/better way to do this that will work? I tried export {Route}; as well, but that didn't help.

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/*"]
        }
      }
    }

Exact error:

TS4023: Exported variable 'detailRoute' has or is using name 'Route' from external module "/Users/chris/<projectname>/node_modules/vue-router/types/router" but cannot be named.

4
  • 1
    See this solution from GitHub: github.com/Microsoft/TypeScript/issues/5711 Commented May 10, 2017 at 18:26
  • Thanks, that's where I started, but it didn't seem to help, or I'm missing something. I imported {Route}, I tried exporting {Route}, I don't know what else I can do to say "Route is in this". Commented May 10, 2017 at 18:35
  • I have not been able to recreate your issue. I am using TypeScript 2.3 and commonjs modules. What are you using? Commented May 10, 2017 at 18:37
  • ES6 modules with Node resolution, and declaration = true; Commented May 10, 2017 at 18:37

12 Answers 12

45

The compiler is failing to figure out the exact shape of detailRoute, because it does not know the shape of Route.

Option 1

One way around this is to import Route from its source, thereby providing the information that the compiler needs to determine the shape of detailRoute.

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

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

Since the index.d.ts file in vue-router (which you were importing in the question) re-exports Route, it does not provide the direct reference to Route that the compiler needed.

Option 2

Another option is to opt detailRoute out of static typing altogether.

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

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

Since any opts-out of static typing, the compiler does not need to figure out the shape of detailRoute.

Option 3

A further is option is what you did in your own answer. Since you provided the type annotation, the compiler again does not need to figure out the shape of detailRoute.

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

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

See also

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

When trying to emit [the module], the compiler needs to write an object type literal... representing the shape of the module. But there isn't a name in scope that refers directly to [Route], so the type "cannot be named" and there's an error.

If you add [a direct] import of [Route]... the error should go away.

Sign up to request clarification or add additional context in comments.

Comments

35

For me it this issue was because I was trying to build a library doing:

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

I changed to:

type Props = {...};

Issue resolved.

7 Comments

This is weird, but yeah it fixed it for me.
This is happening because how typescript handles interface merging versus type aliases, and how bundlers process them differently when building libraries (that's my case).
It would be interesting to understand why it fixes the problem
This fixed it for me too, but it's weird for sure
You could also change it to export interface Props {...}; But still weird that TypeScript is able to use the type, but not the interface
so why do types work but not interfaces? I thought they were interchangeable. late edit: this might have to do with the way dynamic() itself is typed. See this answer.
|
10

Apparently this is the solution to my problem:

  import {Route, RouteConfig} from 'vue-router';


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

Specifying that detailRoute was a RouteConfig (which in turn uses Route) solved the problem. I must have misunderstood how this is supposed to work, but this fixed it.

Comments

9

As others have already pointed out, this is indeed caused by referencing locally imported types.

Without this commit:

- type JsonObject = {
+ export type JsonObject = {

My applications started to break with an error:

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/[email protected]/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.

Exporting JsonObject made that error go away.

What's exceptionally strange is that if you look at the origin of the error, JsonObject then references JsonValue, which is also not exported publicly. But unlike JsonObject, this is causing no issues.

type JsonValue =
  | JsonObject
  | JsonValue[]
  | boolean
  | number
  | string
  | readonly JsonValue[]
  | null
  | undefined;

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

Feels like a bug in or a poorly documented behavior.

If you are an author of the package from which the error originates, the solution is to export the type that's causing the error.

1 Comment

That solves it, no need to move the definitions anywhere, simply exporting was enough. And indeed, it’s only an issue for some types and not others. I recall seeing an explanation on some TS GH issue, but forgot what it is.
6

I came across this when typing a rootReducer, in case anyone else is doing the same. I was importing typed reducers that were composed of other types (state, actions) that I had not also exported.

Short answer: export all your action and state types from the reducers!

Composite types seem not to work to well when their parts are not also exported and you rely on type inference. In this case, inferring the type of the rootReducer (which would be too much to explicitly type if you have more than just a few reducers).

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

1 Comment

I was also dealing with reducer issues, and the solution for me was to remove the unique symbol from RootState before attempting to extend it. The solution for me was: Subtract<RootState, CombinedState<{}>>. Subtract comes from the utility-types npm package
6

An extension to this question for those looking for an answer.

With the following conditions:

Typescript

Version installed: ^4.8.3

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

I encountered this issue with my own library.

The code
  1. Consumed an exported type (Box)
  2. Exported type consumed an unexported type (Dimension)
  3. Consuming exported type via implicit type (no explicit : SomeType annotation)
  4. Error saying that Box is [named but can't be] -- (read: "I can't find the name of something")
The reason

Typescript is looking for the type within Box called Dimension, and failed. "Cannot be named" is an unclear error, but it basically means "Yo, I have no clue what's in this thing" from the context in which it was thrown.

My solution

Export the nested type.

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;
}

Comments

1

Seems to be caused by having local type definitions.

type ABC = {abc: number};
export const function = (): ABC => { return {abc: 123}};

Move the type definitions to a separate file and import them

//types.ts
export type ABC = {abc: number};

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

1 Comment

Same thing, but with enum. Moving to a separate file helped.
0

I got this error while using redux-persist, I moved the types from other files (ie external modules) to above of the declaration of that variable throwing ts-error

Error message of exporting type from external modules

It was complaining about two types(InitialStateOfControlSlice, InitialStateOfProfileSlice), so I just made sure they are in the same file. Typescript compiler happy!!

Comments

0

I had a different situation to the other answers. I created a type definition for an existing package:

// src\@types\dsn-parser\index.d.ts

declare module 'dsn-parser' {
  interface ParsedDSN {
    driver: string
    user: string
    password: string
    host: string
    port: number
    database: string
    params: Record<string, string> | null
  }
  class DSNParser {
    constructor(dsn: string)
    get<K extends keyof ParsedDSN>(key: K): ParsedDSN[K]
    set<K extends keyof ParsedDSN>(key: K, value: ParsedDSN[K]): void
    getDSN(): string
    getParts(): ParsedDSN
  }
  export default DSNParser
}
// src\connectionConfig.ts

import DSNParser from 'dsn-parser'
import env from 'getenv'

const dsn = env('DATABASE_URL')
export const connectionConfig = new DSNParser(dsn).getParts()
// Exported variable 'connectionConfig' has or is using name 'ParsedDSN' from external module "dsn-parser" but cannot be named.ts(4023)

The solution was to export ParsedDNS (the type of the exported connectionConfig) from the definition file. Surprisingly this does not need to be imported into the file with the error, it just needs to be exported from the type definition.

Solution:

declare module 'dsn-parser' {
  export interface ParsedDSN {

Comments

0

In case you see this error in the @radix-ui/react-select package as Exported ... has or is using name 'SelectSharedProps' from external module "/node_modules/radix-ui/node_modules/@radix-ui/react-select/dist/index" but cannot be named., it's a known issue of the latest versions. Check this issue on GitHub: https://github.com/radix-ui/primitives/issues/3501

Comments

-3

Adding a return type fixed the problem for me

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

Gave me the error with SomeType This fixed the problem:

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


Comments

-6

Just add this into tsconfig.json

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

1 Comment

This could use a bit of explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.