Использование пространства имен, распределенного по нескольким файлам модулей в TypeScript

Я начал работу над крупномасштабным проектом машинописного текста.

С самого начала я хочу, чтобы мои файлы были организованы (этот проект будет разделен между множеством разработчиков, поэтому порядок очень необходим).

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

Структура файла:

app.ts
\Classes
---- \Animals
---- ---- Mammals.ts
---- ---- Reptiles.ts

Затем я пытаюсь импортировать все файлы в это пространство имен в app.ts, используя что-то вроде: import * as Animals from "./Classes/Animals"

Что касается самих файлов пространства имен, я безуспешно пробовал следующее:

namespace Animals {
    export class Mammals {
        constructor() {
        }
    }
}

а также:

module Animals {
    export class Reptiles {
        constructor() {
        }
    }
}

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

Я также заметил, что TypeScript 1.5 поддерживает tsconfig.json — однако необходимость вручную добавлять каждый файл на карту — это верный способ создать проблемы, когда разработчики начинают добавлять классы.

ПРИМЕЧАНИЕ. Я использую Visual Studio 2015, TypeScript 1.5 (кажется, не знаю, как проверить). У меня также включена поддержка ES6.


person aaron-bond    schedule 13.08.2015    source источник
comment
Это описано в официальном руководстве (хотя оно может быть устаревшим) typescriptlang.org/Handbook# модули-расщепление-по-файлам   -  person pablochan    schedule 13.08.2015
comment
Спасибо @pablochan - я тоже это видел. Такое обращение к каждому файлу в пространстве имен противоречит здравому смыслу. Можно ли указать пространство имен, а не отдельные файлы?   -  person aaron-bond    schedule 13.08.2015
comment
Нет, если Visual Studio или какой-либо другой инструмент не поддерживает это.   -  person pablochan    schedule 13.08.2015


Ответы (5)


Используйте реэкспорт для создания внешнего модуля, который группирует и предоставляет типы из других модулей:

// Classes/Animals.ts
export * from '.\Animals\Mammals';
export * from '.\Animals\Reptiles';

Затем импортируйте типы из нового модуля, как обычно:

// app.ts
import * as Animals from '.\Classes\Animals'

let dog: Animals.Dog;
let snake: Animals.Snake;

Or

// app.ts
import { Dog, Snake } from '.\Classes\Animals'

let dog: Dog;
let snake: Snake;
person Vadim Macagon    schedule 15.08.2015
comment
Это больше не работает? Это именно то, что я хотел бы сделать, но я продолжаю получать ... Mammals.ts не модуль - person DanielC; 08.12.2017

Нашел способ достичь своей цели, но не с помощью ключевого слова пространства имен.

  1. Классы «Животные», Animal.ts, Mammal.ts и Reptile.ts в пространстве имен.
  2. с индексом ц для ствола.
  3. animals.ts для группировки пространств имен.

Пространство имен животных

Примеры классов:

Классы

index.ts (как бочка)

введите описание изображения здесь

animals.ts (для группировки пространств имен)

введите описание изображения здесь

И вот вам концепция пространства имен.

введите описание изображения здесь

person Val    schedule 20.04.2017
comment
для меня это был правильный ответ, учитывая, что бочки на месте, теперь вы можете иметь многоуровневые пространства имен, я искал что-то вроде api.Animals.Dog, и это позволило мне получить это, однако было бы еще лучше, если бы был способ использования ключевого слова пространства имен в этом подходе - person Aran Dekar; 08.05.2017
comment
Отличный способ решить проблему спасибо! Да, в TS есть пространства имен, но мы не можем использовать их в качестве пространств имен, или есть какой-то скрытый способ? - person Benjamin Piette; 27.08.2020
comment
Этот ответ все еще актуален, учитывая введение синтаксиса /// <reference path="filename.ts" />? - person Richard Simões; 11.02.2021

Внешние модули подразумевают, что вы загружаете модули файл за файлом. И AMD, и CommonJS не имеют пространства имен. Вы можете использовать некоторую постобработку для объединения файлов в один модуль.


Следующее определяет внутренний модуль:

module Animals {
    export class Reptiles {
        constructor() {
        }
    }
}

Вы не должны использовать import для этого. Animals.Reptiles виден где угодно. Единственная цель — загружать скрипты в правильном порядке (например, базовые классы перед наследниками). Поэтому вы должны перечислить все файлы в ts.config или где-то еще. В моем проекте я использую пакеты для папок и имею соглашение добавлять @ к именам файлов базовых классов.

Другим решением является использование внешних модулей: AMD (RequireJS) или CommonJS (Browserify). В этом случае удалите верхний уровень module из объявления. Если один файл содержит только один тип, вы можете экспортировать его как корень:

class Reptiles {
    constructor() {
    }
}

export = Reptiles;

Вы можете ссылаться на модуль по пути к файлу:

import Reptilies = require('..\Animals\Reptilies')
var  reptile = new Reptile();

Или с новыми модулями ES6:

export class Reptiles {
    constructor() {
    }
}

import { Reptiles } from '..\Animals\Reptilies';
person Artem    schedule 13.08.2015
comment
В этом случае, как мне импортировать пространство имен Animals? Если у меня есть пространство имен с 20 классами (все они будут использоваться), мне может понадобиться одна ссылка. По крайней мере, так обстоит дело с другими языками. Кроме того, я заметил, что при поддержке ES 6 код export = Reptiles; кажется обескураживающим, поскольку его нельзя обновить. - person aaron-bond; 13.08.2015

Кажется, нет способа сделать это, используя пространства имен сами по себе (если только вы не хотите использовать Расширение модуля и declare каждый новый элемент добавлять отдельно); однако пространство имен может быть частью класса, который может быть расширен! Это лучшая альтернатива, которую я могу найти:

CoreLibraryTypes.ts

abstract class Types { }
namespace Types { 
    export class TypeA { }
    export class TypeB { }
    export class TypeC { }
}
export { Types };

CoreTypesExtended.ts

import CoreLibraryTypes from "./CoreLibraryTypes";

abstract class Types extends CoreLibraryTypes { }
namespace Types { 
    export class TypeD { }
    export class TypeE { }
    export class TypeF { }
}
export { Types };

Недостатком, конечно, является то, что новые типы будут добавлены только при импорте второго модуля. Первый модуль останется прежним. В идеале было бы неплохо «обновить» пространство имен типов дополнительными типами (например, из плагинов), чтобы расширение модуля поддерживалось более естественно (вместо того, чтобы писать его вручную), но я думаю, что это придется делать до тех пор, пока кто-то понимает, что увеличение модулей путем ручного объявления обновленных определений — это всего лишь пол$$ способа сделать то, что уже делают пространства имен, лол (включая классы, как показано выше, которые уже могут использовать слияние пространств имен как часть класса). ;)

Примечание. В приведенном выше примере я использовал export { Types }; по одной причине — это позволит другим дополнять мои модули. Расширение не поддерживается для экспорта по умолчанию (если только это не желательно - как бы запечатывает его виртуально).

person James Wilkins    schedule 11.04.2019

Если у вас есть собственная библиотека и вы хотите экспортировать несколько файлов, например, из пространства имен, вы можете сделать это:

// index.ts
import * as Animals from './animals';
export { Animals };
person ktretyak    schedule 12.02.2020