Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typescript declare third party modules

How could I declare a third party module which looks like this:

in third party module:

module.exports = function foo(){
  // do somthing
}

in my code:

import * as foo from 'foo-module'; // Can not find a declaration module for ...
foo();
like image 398
Saman Mohamadi Avatar asked May 18 '17 21:05

Saman Mohamadi


People also ask

How do you define a module in TypeScript?

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope (and therefore to modules as well).

How do I add a declaration file to a module?

The error "Could not find declaration file for module" occurs when TypeScript cannot find the type declaration for a module. To solve the error, install the types for the module by running the command from the error message, e.g. npm install -D @types/module-name .


2 Answers

Check out the documentation on working with 3rd party modules.

How to write the declaration depends a lot on how the module was written and what it exports.

The example you've given is a CommonJS module (module.exports = ...) which is not really a valid ES6 module, because ES6 cannot export a function as the module (it can only export function members or a default function).

Update for TypeScript 2.7+

With the added esModuleInterop compiler option you no longer need to use the "namespace hack" shown below for CommonJS modules that have a non-ES6 compatible export.

First, make sure you've enabled esModuleInterop in your tsconfig.json (which is now included by default with tsc --init):

{
  "compilerOptions" {
    ...
    "esModuleInterop": true,
    ...
   }
}

Declare your foo-example in a .d.ts file like this:

declare module "foo-module" {
  function foo(): void; 
  export = foo;
}

Now you can import it as a namespace like you wanted:

import * as foo from "foo-module";
foo();

Or as a default import:

import foo from "foo-module";
foo();

Older workaround

You can declare your foo-example in a .d.ts file like this:

declare module "foo-module" {
  function foo(): void; 
  namespace foo { } // This is a hack to allow ES6 wildcard imports
  export = foo;
}

And import like you wanted:

import * as foo from "foo-module";
foo();

Or like this:

import foo = require("foo-module");
foo();

The documentation has a good resource on declaration files and some templates for various kinds of declaration files.

like image 102
Aaron Beall Avatar answered Oct 16 '22 21:10

Aaron Beall


I had a similar problem. And struggled to add a type definition to my project. Finally, I was able to achieve it using the following steps.

This is some module (just with constants), lets call it some-module - node_modules/some-module/index.js.

'use strict';

exports.__esModule = true;
var APPS = exports.APPS = {
    ona: 'ona',
    tacq: 'tacq',
    inetAcq: 'inetAcq'
};

First I add to tsconfig.json baseUrl and typeRoots

{
  ...
  "compilerOptions": {
    ...
    "baseUrl": "types",
    "typeRoots": ["types"]
  }
  ...
}

Second in my project root I create folder types with same folders structure for the module types/some-module/index.js and place the code:

declare module 'some-module' {
    type Apps =  {
        ona: string;
        tacq: string;
        inetAcq: string;
    };
    let APPS: Apps
}

Finally I can import it in my my-file.ts with typings!

import { APPS } from 'some-module';
like image 37
Michael Klishevich Avatar answered Oct 16 '22 19:10

Michael Klishevich