TypeScript: несколько проектов в решении

Я закончил переносить библиотеку JavaScript на TypeScript в Visual Studio 2012. Всего в нем около 60 классов, каждый из которых определяется в своем собственном файле .ts.

Все классы определены в одном модуле. Я использую ссылки для ссылок на классы, определенные в других файлах. Макет каждого файла выглядит следующим образом:

///<reference path='./../myotherclass.ts' />

module MyModule {

    export class MyClass {
        ...
    }

}

Теперь я создал второй проект в том же решении, которое будет фактическим приложением, используя мою новую портированную библиотеку. Мне нужно каким-то образом включить мою библиотеку, и я предполагаю, для чего предназначена модульная система. Однако я не уверен, какие файлы импортировать, поскольку MyModule распространяется на десятки файлов. Это то, что я могу использовать .d.ts файл для?

Кроме того, чтобы иметь возможность импортировать модуль, он должен быть объявлен с помощью ключевого слова 'export', но если я это сделаю, он больше не будет найден по ссылке.

Кроме того, оба проекта должны быть скомпилированы так, чтобы выход компилятора можно было легко использовать с загрузчиком модуля, например requireJS.

Какой лучший подход для достижения всего этого?

Спасибо!

Ответ 1

Хорошо, позвольте мне начать с того, что "Модуль" может означать разные вещи. Например, существует "шаблон модуля", который создает ваш "MyModule". Насколько я понимаю, TypeScript относится к ним как "внутренние модули" в спецификации языка, и они отличаются от "внешних модулей", которые вы загружаете с помощью чего-то вроде RequireJS. Основное различие заключается в том, что внешние модули ожидают иметь свою изолированную среду с предопределенным объектом "экспорта", который они могут использовать для экспорта своей функциональности.

Взгляните на вывод вашего модуля:

var MyModule;
(function (MyModule) {
    var MyClass = (function () {
        function MyClass() { }
        return MyClass;
    })();
    MyModule.MyClass = MyClass;    
})(MyModule || (MyModule = {}));

Вы видите, что он экспортирует вещи в "MyModule", которые будут доступны глобально для других файлов script, которые вы загружаете, например, с помощью блока html "script". Поскольку вы упомянули, что у вас есть 60 из них, возможно, вы также можете установить компилятор для вывода одного файла, который вы можете включить в разметку, вместо того, чтобы загружать каждый файл по одному.

Перейдя к рассмотрению, посмотрите, что произойдет с выходом, если вы изменили объявление модуля из модуля MyModule {...} "на" export module MyModule {...} ":

(function (MyModule) {
    var MyClass = (function () {
        function MyClass() { }
        return MyClass;
    })();
    MyModule.MyClass = MyClass;    
})(exports.MyModule || (exports.MyModule = {}));

Как вы видите, ваш модуль все еще использует "шаблон модуля", но ему присваивается член "экспорт", означающий, что он предназначен для загрузки, например, node "требует", функция.

В этом случае вы бы хотели использовать свой модуль с этим кодом:

import wrapper = module("./MyModule");
var instance = new wrapper.MyModule.MyClass();

Обратите внимание, что имя "./MyModule" на самом деле относится к имени файла (минус расширение .js), в котором модуль определен (вот почему VS утверждал, что не может найти эти модули для вы). Код должен скомпилироваться примерно так:

var wrapper = require("./MyModule");
var instance = new wrapper.MyModule.MyClass();

Чтобы добавить к этому, вам больше не нужно ничего делать с ключевым словом "module", чтобы иметь модуль. Вы можете просто экспортировать функцию:

// foo.ts
export function foo() {
    ...
};

// some other file in the same dir
import wrapper = module("./foo");
var result = wrapper.foo();

Это работает, потому что функция "foo" будет напрямую назначена "export", которая будет сглажена "wrapper" в другом файле.

Чтобы добавить к этому запутанному беспорядку связанных с модулем вещей, я должен также упомянуть, что модули AMD отличаются друг от друга, поскольку они загружаются асинхронно, в отличие от node "require". Чтобы получить TypeScript для вывода этих данных, вам нужно передать в компилятор параметр "-module AMD".

В любом случае, надеюсь, я достаточно хорошо объяснил ситуацию, пока вы не сможете выяснить, что именно вам нужно/нужно. Тип модулей, которые вы в конечном итоге используете, действительно будет зависеть от того, как вы будете их использовать... т.е. node, веб-интерфейс или какое-то сочетание обоих.