GreatGooeyGoobers
GreatGooeyGoobers

Reputation: 81

How do you write a working .d.ts file for a "complex" vanilla javascript library containing multiple modules/classes?

I am attempting to convert a javascript project to typescript. This project relies on a vanilla javscript library/module with no official type declarations available, meaning I have to write my own.

At present, my project imports the library as follows:

const lib = require('library-name')

All of the modules/classes contained within that library module are imported like so:

const module = lib.module

The compiler reports no errors on the imports, nor does it have when I write my .d.ts file in this form (for non-object modules):

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

However, some of these modules are also OBJECT CLASSES - in other words, one can create instances of them with `new class()'. I attempt to declare them as follows:

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

When I attempt to type a variable or constant as type class_module ie

    let var: class_module = something;

I get an error saying "'class_module' refers to a value, but is being used as a type here." I have triple-checked to make sure I import it into the .ts file and declare it in the .d.ts file in exactly the same way as all the other modules.

To make things more confusing, there is one class that this does not happen with - the compiler does not complain when I use it to type a constant or variable. However, I can not use any of that class's functions, as I always get an error:

This expression is not callable. Type 'typeof ObjectName' has no call signatures.

I don't know if this is relevant, but all of the other classes that give the error about using values as types use "export module", whereas the one that does not throw this error uses a more obscure and foreign (to me) syntax, starting the file with

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

Does the way each module is exported matter?

I have tried all manner of switching things up, importing and declaring modules differently by:

Upvotes: 1

Views: 1138

Answers (1)

Lauren Yim
Lauren Yim

Reputation: 14078

You could define class_module as a class and then extend it with a namespace:

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

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

To use the module:

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()

See also (from the TypeScript handbook):

Upvotes: 1

Related Questions