#typescript
#typescript
Вопрос:
У меня был один файл с большим количеством модулей в нем. Я хотел разделить эти модули на разные файлы и предоставить их из исходного файла. Это связано с тем, что исходный файл имеет> 800 loc и становится очень сложным в управлении.
Итак, я создал файл, содержащий модуль с функциями и интерфейсами:
export module Subsection1 {
export interface Interface {
id: string;
}
export function DoInterfaceStuff(obj: any) {
return = <Interface>{ id: obj }
}
}
У меня есть
import { Subsection1 as Subsection1Base } from "./Subsection1";
export module GodManager {
export type Subsection1 = Subsection1Base amp; (typeof Subsection1Base);
export var Subsection1 = Subsection1Base;
var ObjByID = new Map<string, Subsection1.Interface>();
export function DoThing(source) {
ObjByID.set(source.id, Subsection1.DoInterfaceStuff(source.origin));
}
}
ПРИМЕЧАНИЕ
Новое имя и переменная должны быть доступны извне для текущего класса, потому что я на самом деле загружаю Subsection1Base лениво (в основном, чтобы избежать циклической зависимости).
Комментарии:
1. Почему вы вызываете как интерфейс, так и модуль (пространство имен)
Trigger
? Вместо этого вы могли бы вызвать интерфейсITrigger
. Или вы могли бы поместить интерфейс триггера в модуль триггера.2. Я часто использую этот шаблон для typescript, в основном для извлечения статических методов и членов из классов для очистки кода. Тот факт, что на этот раз это интерфейс, необычен, и я узнал позже, на самом деле, вероятно, не связан с реальной проблемой. Я считаю, что проблема возникает только с любым интерфейсом, определенным в модуле, если модуль повторно экспортируется (он теряет информацию о вводе внутреннего интерфейса).
3. Похоже, в typescript уже есть запрос функции именно для этой функции: github.com/microsoft/TypeScript/issues/4336
Ответ №1:
Ответ @Connor Low указал мне правильное направление, выделив правильную ошибку, но это фактическое решение вопроса.
Из этой проблемы github импортированные модули из других файлов могут быть import export Name = Value
повторно экспортированы с использованием синтаксиса.
Итак, переписав пример кода, решение:
import { Subsection1 as Subsection1Base } from "./Subsection1";
export module GodManager {
export import Subsection1 = Subsection1Base;
var ObjByID = new Map<string, Subsection1.Interface>();
export function DoThing(source) {
ObjByID.set(source.id, Subsection1.DoInterfaceStuff(source.origin));
}
}
И все это работает!
Ответ №2:
Прелюдия
Вопрос изменил код примера, но первоначально они экспортировали module
и interface
с тем же именем и попытался сослаться module
на контекст, в котором interface
действителен только . Хотя не обязательно неправильно разделять имя между двумя разными объявлениями отдельных языковых конструкций, это скрывало истинную проблему, с которой они столкнулись (см. Оригинальный ответ ниже).
Оригинальный ответ
Если мы очистим имена ваших типов, мы сможем довольно быстро выяснить, что здесь не так.
В TriggerEvent мы переименовываем интерфейс Trigger
в ITrigger
:
export interface ITrigger {
// ..
}
export module Trigger {
//...
export function Serialise(restoredEvent: ITrigger) {
//...
}
}
Теперь ActionManager
мы можем увидеть, что пошло не так:
import { Trigger as TriggerBase } from "./TriggerEvent";
export module ActionManager {
type Trigger = TriggerBase amp; (typeof Trigger);
// ^^^^^^^^^^^
// ERROR - Cannot use namespace 'TriggerBase' as a type.
var Trigger = TriggerBase;
var EventsByID = new Map<UUID, Trigger>();
var PrepreparedInputs = new Map<UUID, Trigger.Serialised>();
// ^^^^^^^
// ERROR - 'Trigger' only refers to a type, but is being used as a namespace here.
}
Вы не можете использовать пространство имен (модуль) в качестве типа. (см. Документы). Раньше, поскольку интерфейс и модуль были названы одинаково, TypeScript предоставлял контекстно-соответствующую опцию — интерфейс. Следовательно, ошибок нет! Несмотря на это, у нас все еще есть исходная ошибка 'Trigger' only refers to a type...
, потому что тип — это тип, а не пространство имен (или модуль).
Наконец, ActionManager.Trigger.Serialise(stuff);
не работает, потому что триггер не экспортируется из модуля ActionManager.
Решение
Поскольку вы не можете назначить a module
для a type
, обратитесь к модулю непосредственно в вашем PreparedInputs
:
var PrepreparedInputs = new Map<UUID, TriggerBase.Serialised>();
И, как и в случае с TriggerEvent
, экспортируйте, какие типы / переменные вы хотите использовать вне модуля:
// The interface was renamed to ITrigger in TriggerEvent.
import { Trigger as TriggerBase, ITrigger } from "./TriggerEvent";
export module ActionManager {
export var Trigger = TriggerBase;
export var EventsByID = new Map<UUID, ITrigger>();
export var PrepreparedInputs = new Map<UUID, TriggerBase.Serialised>();
}
Комментарии:
1. Оффтопическая напыщенная речь: разделение статической функциональности на класс модуля, который называется так же, как и сам класс, не сведет всех с ума. Вам просто это не нравится. Этот шаблон очень похож на то, как C разделяет определения в отдельный файл, и я не вижу, чтобы кто-нибудь жаловался на это. Все по-прежнему находится в том же файле, и F12 в каждом редакторе по-прежнему находит нужную функцию, это просто значительно упрощает навигацию по файлу.
2. Я не знаю о разделении определений c (это что-то вроде частичных классов c #?), Но a
module
— это совершенно другой тип вещей, чем aninterface
, что в первую очередь привело к проблеме с запросом (они думали, что включают модуль, но на самом деле это был интерфейс). Я уверен, что есть больше нюансов, чем кто-либо из нас раскрывает.3. Ничего подобного. В C все определения для классов (сигнатуры переменных, сигнатуры методов, общедоступные и защищенные модификаторы) должны быть указаны в файле .h, а содержимое — в файле .cpp. Это также имело место в C. Мой комментарий был ответом на то, что вы сказали, что это сведет всех с ума, кажется очевидным, что у вас мало опыта работы со многими различными языками программирования, поэтому я рекомендую вам как-нибудь попробовать C . Это отличный язык. Связанный: ошибка компиляции, являющаяся неправильной, — это просто ошибка в компиляторе, объединение интерфейсов находится в их документах, поэтому оно поддерживается. Кроме того, я являюсь первоначальным запросчиком.
4. Очень хорошо, я обновил свой ответ. Я по-прежнему считаю, что лучше всего отличать (с помощью уникальных имен) модули от интерфейсов, поскольку в typescript это совершенно разные вещи, но я был слишком широк в своем утверждении.