2012-10-08 11 views
8

No puedo imaginar si es posible tener un "módulo de exportación" distribuido entre varios archivos.¿Cómo distribuir el módulo entre múltiples archivos AMD?

Si tengo Contact.ts archivo:

// file Contact.ts 
export module Contacts { 
    export class Contact { 
     ... 
    } 
} 

y otros ContactView.ts

// file ContactView.ts 
export module Contacts { 
    export class ContactView { 
     model: Contact; // <--- is not recognized 
    } 
} 

Entonces TSC no está reconociendo la clase de contacto. Como puede ver, se declara que Contact y ContactView residen en el mismo módulo y de acuerdo con la especificación debería funcionar.

Estoy construyendo una aplicación compuesta que usa los patrones require.js y AMD, así que TENGO que usar la declaración "exportar módulo".

¿Debo hacer algún tipo de "declaración anticipada" o alguna "importación" engañosa?

Gracias por el asesoramiento.

EDITAR: actualmente cargo cada módulo por separado a través de la importación, pero, si lo nota, crea una enorme pérdida de código y muchas dependencias de "importación". Mi pregunta era si hay una forma de usar el mismo espacio de nombres (es decir, Contactos) para saber el TS que no quiero importar. Estaba buscando el comando normal //, pero no funciona. Incluso probé los archivos de declaración * .d.ts sin éxito hasta el momento.

Respuesta

6

La especificación le permite definir módulos internos en varios archivos (en esencia, los módulos internos hacen referencia al patrón del módulo javascript). Los módulos externos, como los módulos AMD o CommonJS, funcionan con la idea de que cada archivo es el "módulo de código" real, y el espacio de nombre/denominación es irrelevante ya que el módulo se cargará en su propio objeto de todos modos.

Se puede escribir el siguiente código para cargar el módulo Contact.ts interior del módulo ContactView.ts:

// file ContactView.ts  
import mod = module("./Contact"); 

export module Contacts { 
    export class ContactView { 
     model: mod.Contacts.Contact; // <--- will be recognized 
    } 
} 

Y eso debería funcionar bastante bien, pero si quería tener acceso a los contenidos de ambos módulos en otra área (por ejemplo, a hacer un nuevo contacto del mismo), que tendrían que importar esencialmente dos:

import c = module("./Contact"); 
import cv = module("./ContactView"); 

que creo que es lo suficientemente fina, porque usted está indicando claramente sus dependencias. La desventaja es que no compartirán un objeto principal común, por lo que tenerlos a ambos en un patrón de módulo "Contacto" probablemente no sea de gran utilidad.

Otra opción es exportar "Contacto" junto con "ContactView", de la siguiente manera (concedido este código es una tontería porque ya está haciendo exactamente eso a través de la propiedad de modelo de ContactView, pero nunca menos ...):

export module Contacts { 
    export class ContactView { 
     model: mod.Contacts.Contact; 
     constructor() { 
      this.model = new mod.Contacts.Contact(); 
     } 
    } 

    export var Contact = mod.Contacts.Contact; 
} 

Así que podrá acceder a ella después de haber cargado ContactView.

EDITAR: Por cierto, no está limitado a solo exportar módulos a través de "exportar el nombre del módulo {...}", puede exportar cualquier cosa ya que el archivo en sí es el módulo. Por lo tanto, podría tener un archivo que simplemente tenga "exportar función foo() {...}" sin ningún código de patrón de módulo que lo ajuste.

EDIT2 EDIT2: Parece que AMD podría tener funcionalidad para cargar varias dependencias y construir "módulos" a partir de ellas, pero no tengo idea de cómo funcionaría eso en TS, aquí hay un enlace que dice: http://www.adobe.com/devnet/html5/articles/javascript-architecture-requirejs-dependency-management.html (módulos Constructor) .

+0

Esto es exactamente lo que hago ahora: cargar cada módulo por separado a través de la importación, pero, si lo notará, crea un enorme desperdicio de código y cientos de dependencias. Mi pregunta era si hay una forma de usar el mismo espacio de nombres (es decir, Contactos) para saber el TS que no quiero importar. Estaba buscando el comando normal // , pero no funciona. – IgorM

+1

En ese caso, no exporte los Contactos del módulo, simplemente defínalo como 'Contactos de módulo {...}' en todos sus archivos, use /// (esto funciona para módulos internos) para ayudar a TS búsquelos y cree un nuevo archivo para el módulo AMD que solo tiene 'export var contacts = Contacts;' en él para que pueda cargar todo a través de AMD. Deberá asegurarse de que la var que está exportando no tenga el mismo nombre que el módulo, de lo contrario, el código emitido no funcionará. Desafortunadamente no puedo escribir una demostración de código para esto en este momento, pero puedo hacerlo más tarde si es necesario. – nxn

+0

Pensando un poco más, es posible que necesite crear un archivo MAKE que emita cada módulo en su propio archivo JS. – nxn

4

Luché con la misma pregunta por un tiempo, y solo quería compartir lo que estoy haciendo en caso de que alguien más divague sobre esta pregunta.

En primer lugar, define a mí mismo un archivo de referencia que declara todos los archivos en mi módulo:

/// <reference path="_contacts.dependencies.ts" /> 
/// <reference path="../contacts/Contact.ts" /> 
/// <reference path="../contacts/ContactView.ts" /> 
/// <reference path="../contacts/ContactModel.ts" /> 
Nota

que las rutas especificadas en el archivo son en relación con la ubicación del archivo de referencia en sí (_contacts.ts), a diferencia de un archivo de referencia .js. Mi estructura de directorios tiene este aspecto:

modules 
    references // all of the reference files 
     knockout 
     underscore 
     // ... a subfolder for every 3rd party library used 
    contacts 
    commerce 
    // ... other modules at same level as contacts 

Volver al archivo de referencia. La primera línea incluye un archivo de referencia separado que enumera todas las bibliotecas externas utilizadas por el módulo, como subrayado, momento o cualquier otra biblioteca existente para la que tenga un archivo de definición .d.ts. Las líneas restantes son los archivos que componen el módulo.

Dentro de cada archivo que forma parte del módulo, que hacen referencia al archivo anterior:

/// <reference path="../references/_contacts.ts" /> 
module Contacts { 
    export class Contact { 
     public model: ContactModel; 
     // ... 
    } 
} 

Del mismo modo, se puede crear un archivo de referencia único para listar todos los módulos:

/// <reference path="_address.ts" /> 
/// <reference path="_contacts.ts" /> 
/// <reference path="_commerce.ts" /> 

Y simplemente señale esto desde sus archivos fuente.

Esto no resuelve el problema de que el código emitido está en archivos separados. Para ese problema, estoy usando una herramienta de minificación de JavaScript, que es capaz de agrupar varios archivos en un solo archivo fuente. Dependiendo de su configuración de compilación y de las necesidades del caso de uso, es posible que necesite aplicar un envoltorio alrededor del código generado para que funcione como un módulo AMD (aún no muy familiarizado con esa parte).

+0

Me gusta mucho esta solución, ¡gracias! – parliament

+0

En cuanto a la última parte, también puede usar esto para compilar en un solo archivo usando esto en BeforeBuild: La compilación del archivo _references.ts en sí garantiza el orden correcto de cómo se establecieron las referencias. No creo que el indicador de módulo simplemente lo haga funcionar como un módulo de AMD. Creo que para eso necesitas generar un archivo de definición como este: tsc --declarations file1.ts file2.ts file3.ts ... – parliament

+0

En realidad, acabo de resolver un error relacionado con este enfoque aquí: http: //typescript.codeplex .com/workitem/836 – parliament

Cuestiones relacionadas