Безопасный импорт модулей TypeScript из путей, известных только во время выполнения

#typescript

#typescript

Вопрос:

Допустим, у меня есть файловое дерево с кодом и ресурсами TypeScript, которые я обслуживаю с некоторого произвольного URL (например, между CDN и местоположением отладки) — я хочу иметь возможность импортировать корень этого модуля и разрешить правильному импорту остальной части дерева, когда это необходимо(т. е. Без необходимости указывать путь загрузки более одного раза).

В JavaScript я, вероятно, мог бы сделать что-то вроде этого:

 export class MyModule {
    private dependentModulePromise;

    constructor(rootpath) {
        this.dependentModulePromise = import(rootpath   '/dependentModule');
    }
}
  

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

Я попробовал это расширение:

 import * as DependentModule from '/dependentModule';

export class MyModule {
    private dependentModulePromise: Promise<DependentModule>;

    constructor(rootpath) {
        this.dependentModulePromise = import(rootpath   '/dependentModule') as Promise<DependentModule>;
    }
}
  

но в итоге я получаю сообщение об ошибке, сообщающее мне, что пространство DependentModule имен не может использоваться в качестве типа.

Комментарии:

1. Проблема заключается в import * . Когда вы импортируете все из файла и присваиваете ему имя like DependentModule , typescript видит это как пространство имен, а отдельные элементы экспортируются как значения в этом пространстве имен. Есть ли /dependentModule экспорт по умолчанию?

2. @LindaPaiste Обязательно ли он должен быть? Если это произойдет, я мог бы заставить это работать, хотя я бы предпочел иметь возможность импортировать произвольный модуль, если бы мог.

3. Честно говоря, я не знаю, действительно ли это решит вашу проблему. Я просто знаю, что import * является источником текущей ошибки.

Ответ №1:

Вот что-то очень близкое: если /dependentModule имеет экспорт по умолчанию, вместо того, чтобы пытаться экспортировать пространство имен, тогда он работает нормально.

 // Here, dependentModule exports a class
import { default as DependentModule_TYPE_ONLY } from '/dependentModule';

export class MyModule {
    private dependentModulePromise: Promise<new () => DependentModule_TYPE_ONLY>;

    constructor(rootpath) {
        this.dependentModulePromise = import(rootpath   '/dependentModule') as Promise<new () => DependentModule>;
    }
    
    public async doStuffWithDependentModule() {
        const DependentModule = await this.dependentModulePromise;
        const m = new DependentModule();
        // now do typesafe stuff with m
    }

}
  

Очевидно, что лучший маршрут — это если этот экспорт по умолчанию реализует некоторый интерфейс или форму типа, найденную в другом месте, чтобы обещание можно было использовать для этого, а не как экземпляр класса (т. Е. Если DependentModule implements IInterfaceOfInterest , то import обещание имеет тип Promise<new () => IInterfaceOfInterest> ).