Typescript: TS4023: La variable exportada 'X' tiene o usa el nombre 'Y' del módulo externo 'a / file / path' pero no se puede nombrar

Creado en 18 nov. 2015  ·  24Comentarios  ·  Fuente: microsoft/TypeScript

Estoy intentando crear un conjunto de módulos externos de TypeScript de la siguiente manera:

// ClassA.ts
export default class ClassA {
  public method() { return true; } 
}

// ModuleB.ts
import ClassA from './ClassA';
var moduleB = {
  ClassA: ClassA
};
export default moduleB;

// ModuleA.ts
import moduleB from './ModuleB';
var moduleA = {
  moduleB: moduleB
}
export default moduleA;

La idea es que se compile y se proporcione como una biblioteca. El plan es que el consumidor de la biblioteca instanciará una instancia de ClassA de la siguiente manera:

import moduleA from './ModuleA';
var anInstance = moduleA.moduleB.ClassA();

Parece que se está compilando en el JS esperado, pero recibo un error del compilador del que estoy luchando por encontrar más información.

Using tsc v1.6.2
.../src/ModuleA.ts(3,5): error TS4023: Exported variable 'moduleA' has or is using name 'ClassA' from external module ".../src/ClassA" but cannot be named.

¿Alguien aquí puede arrojar algo de luz sobre este tema? ¿Tiene sentido lo que estoy tratando de hacer?

Question

Comentario más útil

FWIW, generalmente obtendrá respuestas más rápidas en Stack Overflow, pero aquí respondemos preguntas bien redactadas.

El problema aquí es que está usando la bandera --declaration , pero no ha proporcionado una forma para que el compilador haga su trabajo.

Al intentar emitir ModuleA.d.ts , el compilador necesita escribir un tipo de objeto literal (por ejemplo, { moduleB: { classA: *mumble?* } } ) que represente la forma del módulo. Pero no hay un nombre en el alcance que se refiera directamente a classA , por lo que el tipo "no se puede nombrar" y hay un error.

Si agrega import de ClassA a ModuleA.ts , el error debería desaparecer.

Todos 24 comentarios

Oh, si este no es un lugar adecuado para hacer esta pregunta. Házmelo saber y con gusto lo publicaré en otro medio.

FWIW, generalmente obtendrá respuestas más rápidas en Stack Overflow, pero aquí respondemos preguntas bien redactadas.

El problema aquí es que está usando la bandera --declaration , pero no ha proporcionado una forma para que el compilador haga su trabajo.

Al intentar emitir ModuleA.d.ts , el compilador necesita escribir un tipo de objeto literal (por ejemplo, { moduleB: { classA: *mumble?* } } ) que represente la forma del módulo. Pero no hay un nombre en el alcance que se refiera directamente a classA , por lo que el tipo "no se puede nombrar" y hay un error.

Si agrega import de ClassA a ModuleA.ts , el error debería desaparecer.

Hola Ryan, gracias por el consejo RE stack overflow y el consejo: agregar la importación a ModuleA hizo que las cosas se compilaran como se esperaba.

Un poco de contexto aquí: mi objetivo aquí es generar declaraciones para mis módulos externos. (¿Algo que creo que todavía no está funcionando? # 5039?) Esta importación puede ser completamente necesaria, pero se siente un poco extraño que ModuleA necesite importar los símbolos que el módulo B ya exporta. El resultado es que cada vez que agrego a la exportación de objetos de ModuleB , tendré que agregar la importación a ModuleA , ya sea directamente:

import {moduleB} from './moduleB';
import {ClassA} from './ClassA';

O a través de ModuleB (en un esfuerzo por reducir la especificación de rutas para ClassA en ambos lugares):

import {moduleB, ClassA} from './moduleB';

Sé muy poco sobre el compilador de TS, por lo que tal vez lo que estoy diciendo sea completamente irreal, pero al principio pensé que el compilador podría deducir que ModuleB está exportando un objeto con N símbolos, así que ModuleA necesita esos símbolos? La información de importación para ModuleB ya está allí, ¿podría ModuleA usarla? ¿O sería eso imposible porque la importación de ClassA es completamente interna a ModuleB , por lo que no hay forma de que el compilador pueda deducir el tipo de ClassA al crear definiciones para ModuleA ?

Gracias nuevamente por tomarse el tiempo para responder. He solucionado mi problema ahora, por lo que lo anterior es principalmente curiosidad; no hay prisa por responder.

No estoy seguro de lo que estás diciendo exactamente. ¿Cómo debería verse ModuleA.d.ts en esta propuesta?

El compilador no agregará dependencias (es decir, declaraciones de importación) que no existían en el código de usuario cuando emite declaraciones. el error que está obteniendo significa que el compilador está intentando escribir una anotación de tipo para una declaración exportada pero no pudo. esto puede tener una de dos razones, o el nombre no es accesible, es decir, no se importa en el módulo actual, o hay una declaración que está ocultando la declaración original.

en ambos casos, su solución es agregar una anotación de tipo explícita, si agrega cualquier anotación de tipo, se emitirá literalmente en la salida; la otra opción es asegurarse de que el nombre sea accesible, es decir, que tiene una importación al módulo y comprende lo que eso significa para los usuarios que están importando su módulo.

@mhegazy dijo:

El compilador no agregará dependencias (es decir, declaraciones de importación) que no existían en el código de usuario cuando emite declaraciones.

El problema es que no siempre necesito las declaraciones de importación en el código (obviamente, ya que funciona sin --declarations ), y su inclusión es ruidosa, lo que hace que cosas como tslint quejen del "importación no utilizada". Puedo ver por qué no querría que el compilador agregue dependencias al javascript emitido, pero ¿cuál es el problema de agregarlas a las declaraciones de emisión?

no dude en registrar un problema para realizar un seguimiento de esta sugerencia. las importaciones racionales son una declaración de dependencia, y el compilador no debería crear una para usted a menos que usted le indique que lo haga.

Esto podría tener consecuencias más profundas.

Considere moduleA -> moduleB -> moduleC -> moduleD .

moduleB es el que necesita hacer import { ABC } from 'moduleA' para solucionar este problema.

Cuando moduleC usa moduleB y exporta su firma, nuevamente falla al compilar porque moduleB necesita ABC de moduleA pero esta vez moduleB no lo exportó.

Esto significa que:

  1. moduleC debe tener una dependencia estricta de moduleA e importar ABC
  2. moduleB no solo debe importar, sino también reexportar ABC y luego moduleC importa.

Si moduleD hace cosas similares, entonces básicamente necesitas conocer toda la cadena de dependencias.

No pude probar esto para demostrar que es el caso porque estoy usando typings y hay un problema que me bloquea, así que: https://github.com/typings/typings/issues/625 ~~

EDITAR: Puedo reproducirlo y, de hecho, mi moduleD necesita hacer referencia a moduleA para realizar la importación.
En mi ejemplo:

  • moduleA => redux
  • moduleB => redux-thunk
  • moduleC => código personalizado encima de redux-thunk
  • moduleD => alguna biblioteca
  • ABC => Dispatch interfaz en redux

Tengo el mismo problema descrito por @unional

Vuelva a abrir este problema, los problemas descritos por @unional son muy realistas y esto hace que sea muy difícil agregar bibliotecas intermedias / auxiliares en la parte superior de las bibliotecas mientras se usan los mismos tipos que el módulo original que estamos reexportando.

Emita https://github.com/Microsoft/TypeScript/issues/9944 pistas agregando la importación en la fase de emisión de declaración.

¡Gracias!

El problema de agregar la importación es que con noUnusedLocals el compilador se quejará de que el tipo no se está utilizando. Podría agregar una anotación de tipo explícita, pero luego no obtengo inferencia. Ejemplo:

class Whatever {
  fetch(uri: string): Promise<void> { }
  ensureFetched = MemoizedFunction<(uri: string) => Promise<void>> = memoize((uri: string) => this.fetch(uri))
}

Me gustaría omitir la anotación de tipo para ensureFetched

Encontré una solución para esto:
en tsconfig: include: [ ..., "node_modules/@your_scope/your_library" ]
buena suerte y diviértete: smiley:

@ salim7 esto ralentiza sus tiempos de compilación (porque está recompilando una biblioteca que ya debería haber sido compilada) y lo obliga a usar el mínimo común denominador de configuración de rigor con la biblioteca de destino.

@mhegazy, el problema se ha reproducido en el siguiente escenario:

import * as Foo from "./Foo";

export class Bar {
    baz = new Foo.Baz(); // Compiler forgot "Foo." prefix in the type, and throws this error, because "Baz" without perfix is not imported.
    getBaz() { // All the same
       return new Foo.Baz();
    }
}

La solución es especificar el tipo explícito:

import * as Foo from "./Foo";

export class Bar {
    baz: Foo.Baz = new Foo.Baz(); // ok
    getBaz(): Foo.Baz { // ok
       return new Foo.Baz();
    }
}

No puedo reproducir esto usando el ejemplo anterior. presente un nuevo error y proporcione más contexto para poder reproducir el problema.

@PFight ¡ Gracias! ¡Eso fue todo para mí!

Acabo de enfrentar este problema al usar:

export { IMyInterface } from './file'
````

The solution was to do this:
```ts
import { IMyInterface } from './file'
export { IMyInterface }

Pero esto realmente no debería ser necesario tbh.

¿Alguien ha descubierto cómo lidiar con noUnusedLocals ?

@yordis // @ts-ignore

@pelotom sí, esto es completamente mi culpa,

Estaba pensando en una cosa y escribí otra.

¿Typecript solucionó el problema entre noUnusedLocals y las declaraciones?

Mi solución actual, que me parece un dolor total,

import {SomeInterface} from "./SomeFile";

const _dummySomeInterface : undefined|SomeInterface = undefined;
_dummySomeInterface;

//Code that implicitly uses SomeInterface

Evita noUnusedLocals , también permite la inferencia de tipos para interfaces genéricas, siempre que sea posible.

¿Fue útil esta página
0 / 5 - 0 calificaciones