Я пытаюсь создать набор внешних модулей TypeScript следующим образом:
// ClassA.ts
export default class ClassA {
public method() { return true; }
}
// ModuleB.ts
import ClassA from './ClassA';
var moduleB = {
ClassA: ClassA
};
export default moduleB;
// ModuleA.ts
import moduleB from './ModuleB';
var moduleA = {
moduleB: moduleB
}
export default moduleA;
Идея состоит в том, что это будет скомпилировано и предоставлено как библиотека. План состоит в том, что потребитель библиотеки создаст экземпляр ClassA следующим образом:
import moduleA from './ModuleA';
var anInstance = moduleA.moduleB.ClassA();
Похоже, что он компилируется до ожидаемого JS, но я получаю сообщение об ошибке компилятора, о котором я изо всех сил пытаюсь найти дополнительную информацию.
Using tsc v1.6.2
.../src/ModuleA.ts(3,5): error TS4023: Exported variable 'moduleA' has or is using name 'ClassA' from external module ".../src/ClassA" but cannot be named.
Может ли кто-нибудь пролить свет на эту проблему? Имеет ли смысл то, что я пытаюсь сделать?
О, если это не подходящее место, чтобы задать этот вопрос. Пожалуйста, дайте мне знать, и я буду рад опубликовать его на другом носителе.
FWIW вы обычно получите более быстрые ответы на Stack Overflow, но мы задаем здесь хорошо сформулированные вопросы.
Проблема здесь в том, что вы используете флаг --declaration
, но не предоставили компилятору возможность выполнять свою работу.
При попытке сгенерировать ModuleA.d.ts
компилятор должен написать литерал типа объекта (например, { moduleB: { classA: *mumble?* } }
), представляющий форму модуля. Но в области нет имени, которое напрямую ссылается на classA
, поэтому это тип «не может быть назван» и возникает ошибка.
Если вы добавите import
из ClassA
к ModuleA.ts
, ошибка должна исчезнуть.
Привет, Райан - спасибо за совет RE stack overflow и за совет - добавление импорта в ModuleA
привело к компиляции, как и ожидалось.
Небольшой контекст здесь - моя цель здесь действительно создать объявления для моих внешних модулей. (Что-то, как мне кажется, еще не совсем работает? # 5039?) Этот импорт может быть полностью необходимым, но для ModuleA
кажется немного странным необходимость импортировать символы, которые уже экспортирует moduleB. В результате каждый раз, когда я добавляю экспорт объекта ModuleB
, мне нужно будет добавить импорт в ModuleA
- либо напрямую:
import {moduleB} from './moduleB';
import {ClassA} from './ClassA';
Или через ModuleB
(чтобы уменьшить количество указаний путей для ClassA
в обоих местах):
import {moduleB, ClassA} from './moduleB';
Я очень мало знаю о компиляторе TS - возможно, то, что я говорю, совершенно нереалистично, но на первый взгляд кажется, что компилятор может сделать вывод, что ModuleB
экспортирует объект с N символами на нем, поэтому ModuleA
нужны эти символы? Информация об импорте для ModuleB
уже есть - может ли ModuleA
использовать это? Или это было бы невозможно, потому что импорт для ClassA
является полностью внутренним для ModuleB
, поэтому компилятор не может определить тип для ClassA
при создании определений для ModuleA
?
Еще раз спасибо за то, что нашли время ответить. Я разобрался со своей проблемой, так что вышесказанное в основном связано с любопытством - не нужно спешить с ответом.
Я не совсем понимаю, что вы говорите. Как должен выглядеть ModuleA.d.ts
в этом предложении?
Компилятор не будет добавлять зависимости (т. Е. Операторы импорта), которых не было в пользовательском коде, когда он генерирует объявления. полученная ошибка означает, что компилятор пытается написать аннотацию типа для экспортированного объявления, но не может. это может иметь одну из двух причин: либо имя недоступно, то есть не импортировано в текущий модуль, либо есть объявление, которое заменяет исходное объявление.
в обоих случаях ваша работа - добавить явную аннотацию типа, если вы добавите какую-либо аннотацию типа, она будет дословно выдана на выходе; другой вариант - убедиться, что имя доступно, т.е. у вас есть импорт в модуль, и вы понимаете, что это значит для ваших пользователей, которые импортируют ваш модуль.
@mhegazy сказал:
Компилятор не будет добавлять зависимости (т. Е. Операторы импорта), которых не было в пользовательском коде, когда он генерирует объявления.
Проблема в том, что мне не всегда нужны операторы импорта в коде (очевидно, поскольку он работает без --declarations
), и их включение является шумным, заставляя такие вещи, как tslint
жаловаться на «неиспользованный импорт». Я понимаю, почему вы не хотите, чтобы компилятор добавлял зависимости к испускаемому javascript, но в чем проблема с их добавлением к испускающим объявлениям?
не стесняйтесь регистрировать проблему, чтобы отслеживать это предложение. рациональным было то, что импорт - это объявление зависимости, и компилятор не должен создавать его для вас, если вы не дадите ему указание.
Это могло иметь более глубокие последствия.
Рассмотрим moduleA
-> moduleB
-> moduleC
-> moduleD
.
moduleB
- это то, что нужно сделать import { ABC } from 'moduleA'
чтобы обойти эту проблему.
Когда moduleC
использует moduleB
и экспортирует свою подпись, он снова не компилируется, потому что moduleB
требует ABC
от moduleA
но на этот раз moduleB
не экспортировал.
Это означает либо:
moduleC
должен иметь жесткую зависимость moduleA
и импортировать ABC
moduleB
необходимо не только импортировать, но и повторно экспортировать ABC
а затем moduleC
импортирует его.Если moduleD
делает аналогичные вещи, то в основном вам нужно знать всю цепочку зависимостей.
Я не смог проверить это, чтобы доказать, что это так, потому что я использую typings
и есть проблема, которая блокирует меня: https://github.com/typings/typings/issues/625 ~~
РЕДАКТИРОВАТЬ: я могу воспроизвести его, и действительно, мой moduleD
должен ссылаться на moduleA
для импорта.
В моем примере:
moduleA
=> redux
moduleB
=> redux-thunk
moduleC
=> пользовательский код поверх redux-thunk
moduleD
=> некоторая библиотекаABC
=> Dispatch
интерфейс в redux
У меня такая же проблема, описанная @unional
Пожалуйста, откройте эту проблему еще раз, проблемы, описанные @unional , очень реалистичны, и это очень затрудняет добавление каких-либо промежуточных / вспомогательных библиотек поверх библиотек при использовании тех же типов, что и исходный модуль, который мы повторно экспортируем.
Проблема https://github.com/Microsoft/TypeScript/issues/9944 отслеживает добавление импорта на этапе создания объявления.
Спасибо!
Проблема с добавлением импорта заключается в том, что с noUnusedLocals
компилятор будет жаловаться на неиспользуемый тип. Я мог бы добавить явную аннотацию типа, но тогда я не получаю вывода. Пример:
class Whatever {
fetch(uri: string): Promise<void> { }
ensureFetched = MemoizedFunction<(uri: string) => Promise<void>> = memoize((uri: string) => this.fetch(uri))
}
Я хотел бы опустить аннотацию типа для ensureFetched
Я нашел обходной путь для этого:
в tsconfig: include: [ ..., "node_modules/@your_scope/your_library" ]
удачи и удачи: smiley:
@ salim7 это замедляет время компиляции (потому что вы перекомпилируете библиотеку, которая уже должна была быть скомпилирована) и заставляет вас использовать наименьший общий знаменатель параметров строгости с целевой библиотекой.
@mhegazy проблема воспроизведена в следующем сценарии:
import * as Foo from "./Foo";
export class Bar {
baz = new Foo.Baz(); // Compiler forgot "Foo." prefix in the type, and throws this error, because "Baz" without perfix is not imported.
getBaz() { // All the same
return new Foo.Baz();
}
}
Решение - указать тип явным образом:
import * as Foo from "./Foo";
export class Bar {
baz: Foo.Baz = new Foo.Baz(); // ok
getBaz(): Foo.Baz { // ok
return new Foo.Baz();
}
}
Я не могу воспроизвести это на примере выше. пожалуйста, сообщите о новой ошибке и предоставьте более подробный контекст, чтобы можно было воспроизвести проблему.
@PFight Спасибо! Это было для меня!
Я только что столкнулся с этой проблемой при использовании:
export { IMyInterface } from './file'
````
The solution was to do this:
```ts
import { IMyInterface } from './file'
export { IMyInterface }
Но в этом действительно не должно быть необходимости.
Кто-нибудь придумал, как бороться с noUnusedLocals
?
@yordis // @ts-ignore
@pelotom да, это полностью моя вина,
Я думал об одном, а писал о другом.
Устранена ли в Typescript проблема между noUnusedLocals
и объявлениями?
Мой текущий обходной путь, который кажется мне полной болью,
import {SomeInterface} from "./SomeFile";
const _dummySomeInterface : undefined|SomeInterface = undefined;
_dummySomeInterface;
//Code that implicitly uses SomeInterface
Избегает noUnusedLocals
, разрешает вывод типов и для универсальных интерфейсов, где это возможно.
Самый полезный комментарий
FWIW вы обычно получите более быстрые ответы на Stack Overflow, но мы задаем здесь хорошо сформулированные вопросы.
Проблема здесь в том, что вы используете флаг
--declaration
, но не предоставили компилятору возможность выполнять свою работу.При попытке сгенерировать
ModuleA.d.ts
компилятор должен написать литерал типа объекта (например,{ moduleB: { classA: *mumble?* } }
), представляющий форму модуля. Но в области нет имени, которое напрямую ссылается наclassA
, поэтому это тип «не может быть назван» и возникает ошибка.Если вы добавите
import
изClassA
кModuleA.ts
, ошибка должна исчезнуть.