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?
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:
moduleC
debe tener una dependencia estricta de moduleA
e importar ABC
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 bibliotecaABC
=> 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.
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 aclassA
, por lo que el tipo "no se puede nombrar" y hay un error.Si agrega
import
deClassA
aModuleA.ts
, el error debería desaparecer.