Как вы пишете рабочий файл .d.ts для «сложной» библиотеки javascript vanilla, содержащей несколько модулей/классов?

#typescript #class #module #declaration #.d.ts

Вопрос:

Я пытаюсь преобразовать проект javascript в машинописный текст. Этот проект основан на ванильной библиотеке/модуле javscript, в которой отсутствуют официальные объявления типов, что означает, что я должен написать свой собственный.

В настоящее время мой проект импортирует библиотеку следующим образом:

const lib = require('library-name')

Все модули/классы, содержащиеся в этом библиотечном модуле, импортируются следующим образом:

const module = lib.module

Компилятор не сообщает об ошибках при импорте, и их нет, когда я пишу свой файл .d.ts в этой форме (для необъектных модулей).:

   declare module 'library-name' {
    ...
    declare module 'module1' {
      function functionName: functionType;
    }
    ...
  }
 

Однако некоторые из этих модулей также являются КЛАССАМИ ОБЪЕКТОВ — другими словами, их экземпляры можно создавать с помощью » нового класса ()». Я пытаюсь объявить их следующим образом:

   declare module 'library-name' {
    declare module class_module{
      class class_module {
        function1(parameter: type): functionType;
        function2(): void;
      }    
    
      export = class_module;
    }
  }
 

Когда я пытаюсь ввести переменную или константу в качестве типа class_module, т. Е.

     let var: class_module = something;
 

Я получаю сообщение об ошибке «‘class_module’ относится к значению, но используется здесь в качестве типа». Я трижды проверил, чтобы убедиться, что я импортирую его в файл .ts и объявляю его в файле .d.ts точно так же, как и все остальные модули.

Чтобы сделать вещи более запутанными, есть один класс, с которым этого не происходит — компилятор не жалуется, когда я использую его для ввода константы или переменной. Однако я не могу использовать ни одну из функций этого класса, так как всегда получаю сообщение об ошибке:

Это выражение не может быть вызвано. Тип «Имя объекта typeof» не имеет сигнатур вызовов.

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

   (function(exports) {
 
 and ending with
 
   exports.ClassName = ClassName;
  })(typeof exports !== 'undefined' ? exports : this);
 

Имеет ли значение способ экспорта каждого модуля?

Я перепробовал все способы переключения, импорта и объявления модулей по-разному с помощью:

  • используя «импорт {модуль1, модуль2, … модуль n} из»модуля»»
  • объявление модулей в качестве пространств имен, интерфейсов, классов (напрямую), что у вас есть в .d.ts
  • … и различные другие снимки в темноте. Кажется, ничто не имеет большого значения или какой-либо разницы.

Ответ №1:

Вы можете определить class_module как класс, а затем расширить его с помощью пространства имен:

 declare module 'library-name' {
  declare namespace class_module {
    export = class_module
  }

  declare class class_module {
    function1(parameter: type): functionType
    function2(): void
  }
}
 

Для использования модуля:

 import {class_module} from 'library-name'
// or
import lib from 'library-name'
const {class_module} = lib
type class_module = lib.class_module

const foo: class_module = new class_module()
 

См. Также (из руководства по машинописи):

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

1. Это сработало. Ну, отчасти так оно и было. Объявление пространства имен ничего не дало. «импорт {class_module} из» имени библиотеки » ничего не сделал. Однако третья часть этого — даже без этих первых двух («импорт библиотеки из «имени библиотеки»… введите class_module = lib.class_module») сделал свое дело. Я предполагаю, что это сработало, потому что он явно объявил модуль как тип?

2. Пока это работает, это похоже на «халтурное» решение. Будет ли это в целом считаться хорошей практикой?

3. Мне пришлось сделать еще несколько хитрых вещей, чтобы eslint перестал жаловаться на другие вещи, связанные с машинописью, в моем коде.