Общее использование TypeScript для модулей / пространств имен - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть стандартная веб-страница (не приложение, отображаемое с помощью angular, реагировать, vue и т. Д.), Использующее jQuery и другие библиотеки.

Я хочу интегрировать передовой опыт с TypeScript.Каков наилучший способ сделать это?

Моя текущая идея состоит в том, чтобы иметь 3 файла:

  1. index.d.ts (описывает типы моего модуля)
  2. test.ts (реализация типов, описанных в index.d.ts)
  3. page.js (файл, который использует JavaScript, определенный в test.js - вывод из test.ts)

В настоящее время у меня есть это содержимое:

index.d.ts

// Type definitions for test 1.0.0
// Project: Test
// Definitions by: Author Name

/// <reference path="../../lib/@types/jquery/index.d.ts" />
declare namespace TestNS {
    export class TestClass {
        // Fields
        element: JQuery;
        value: string;

        constructor(element: JQuery, val: string);

        OnCreate();

        static AttachToJQuery(jq: JQueryStatic): void;
    }

    interface JQuery {
        TestClass(element: JQuery, val?: string): TestNS.TestClass;
    }

    interface JQueryStatic {
        TestClass(element: JQuery, val?: string): TestNS.TestClass;
    }
}

Test.ts (загружено 2-е, послеjQuery)

/// <reference path="../../lib/@types/jquery/index.d.ts" />
/// <reference path="./index.d.ts" />

export namespace TestNS {
    export class TestClass {
        // Fields
        element: JQuery;
        value: string;

        constructor(element: JQuery, val: string) {
            this.element = element;
            this.value = val;
            this.OnCreate();
        }

        OnCreate() {
            this.element.data('test-value', this.value);
        }

        static AttachToJQuery(jq: JQueryStatic) {
            //no jQuery around
            if (!jq) {
                return false;
            }

            jq.fn.extend({
                TestNS: function(newVal) {
                    return this.each(function() {
                        var obj = jq(this);
                        new TestNS.TestClass(obj, newVal);

                    });
                }
            });
        }//attach to jquery method (to easily work with noconflict mode)
    }//test class
}

page.js (загружен последним)

let newJquery:JQueryStatic = jQuery.noConflict();
TestNS.TestClass.AttachToJQuery(newJquery);

let testElems = newJquery(".testClass");
testElems.TestClass();

Моя цель - аккуратно организовать мой код в пространстве имен в машинописи.как на странице (но это делает в машинописном тексте ошибки, связанные с дублирующимися идентификаторами), а также является модульным и расширяемым.Я понимаю, что я должен публиковать свои типы в каталоге "node_modules / @ types", но я просто хочу, чтобы они все сейчас инкапсулированы в этом модуле.

Я попытался использовать модуль и импортировать то, что определено в index.d.ts, но TypeScript говорит, что я не могу импортировать этот файл, и что имя модуля не может быть найдено.Я узнал, что если я использую модуль, он должен сопровождаться загрузчиком, таким как CommonJS, RequireJS или AMD, но я бы предпочел пока избегать этого (если это не ужасная практика, так как я хочуминимизировать уровни сложности на данный момент).

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

Есть лихороший способ пойти по этому поводу?

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Если вы хотите, чтобы все работало без загрузчика модулей, вам придется внести несколько изменений.Прежде всего, стоит отметить, что TypeScript поддерживает 2 основных способа модуляции кода, пространств имен и модулей.

ПРИМЕЧАНИЕ. Немного сбивает с толку нюанс: ключевые слова namespace и module могут использоваться взаимозаменяемо и сами по себе не определяют, является ли объект модулем или пространством имен.

1) модули (ранее называвшиеся внешними модулями) - они используют типичный импорт, экспорт и требуют семантики и требуют загрузчика модулей и, предпочтительно, какого-либо сборщика.Для этого шаблона каждый файл считается модулем.Любой файл, содержащий любые операторы импорта или экспорта, будет считаться внешним модулем компилятором TypeScript.

2) пространства имен (ранее называвшиеся внутренними модулями) - этот шаблон поддерживает пространства имен, которые могут занимать несколько файлов.Это тип модуля, который вам нужно использовать, если вы не хотите использовать загрузчик модулей.Использование этого шаблона становится все менее распространенным, но это все еще вариант, если вы хотите использовать его по любой причине.Чтобы использовать этот тип модульности, в файле не должно быть операторов импорта или экспорта.

Вот документы на namespaces https://www.typescriptlang.org/docs/handbook/namespaces.html

Предполагая, что вы хотите продолжитьИсходный план, вам нужно будет настроить пару вещей в своем коде.

1) Как уже упоминалось @sbat, ваш index.d.ts повторно объявляет ваше пространство имен и типы классов.Это, вероятно, приводит к ошибкам определения дубликатовВы можете заменить все содержимое простым переопределением интерфейса JQuery.

/** Extend the JQuery interface with custom method. */
declare interface JQuery {
    TestNS: () => TestNS.TestClass
}

2) Убедитесь, что у вас нет экспорта или импорта верхнего уровня.В частности, вы захотите удалить export из вашего пространства имен в test.ts.Это сделает ваш модуль internal один вместо external один.

namespace TestNS {
    export class TestClass {
        ...
    }
}
0 голосов
/ 29 ноября 2018

Если вы хотите просто попробовать TypeScript в простом проекте, я бы посоветовал вам немного упростить:

  • Удалить index.d.ts.Файлы определений описывают существующий код JavaScript, поэтому TypeScript знает о типах в нем.У вас нет такой ситуации в вашем проекте, нет необходимости повторять информацию о типе, которая уже есть в вашем test.ts, вы можете безопасно удалить этот файл.

  • Просто создайте свойtest.ts в test.js.Убедитесь, что ваш jquery .d.ts находится там, где и должен быть.

  • Удалите page.js, просто закодируйте все в test.ts для теста.Как только вы сделаете это, вы можете реорганизовать его.

Однако, если ваша цель состоит в том, чтобы ваш код был модульным и расширяемым, рекомендуемый подход заключается в том, чтобы действительно использовать модули:

Начиная с ECMAScript 2015, модулиявляются родной частью языка и должны поддерживаться всеми совместимыми реализациями движка.Таким образом, для новых проектов модулей будет рекомендуемый механизм организации кода.

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

Для использования модулей в производственной среде в браузере вам потребуется:

  • Bundler.Инструмент, который будет вызывать TypeScript для создания ваших отдельных модулей TS, а затем объединять результаты сборки в один файл javascript.Затем вы включите этот единственный файл в ваш HTML.WebPack, пожалуй, проще всего запустить: https://webpack.js.org/concepts/

  • Диспетчер пакетов.Инструмент, который устанавливает и управляет версиями сторонних модулей.https://www.npmjs.com/

Это большая область для изучения, но я не думаю, что это перебор.Если ваш код является модульным (даже если это всего 2 модуля), вам нужна инфраструктура для объединения и загрузки ваших модулей тем или иным способом.Есть несколько вариантов с различными преимуществами и компромиссами, но принципиально нет пути к этому.

...