Typescript: What is the correct way to write a .d.ts file for a node module, which is referenced in package.json?

Created on 27 Apr 2016  路  11Comments  路  Source: microsoft/TypeScript

So, i am working on a small module written in JS, but I want to make it easy to use that module in TypeScript as well. It adds a wrapper with some additional functionality around an existing JS module.

In my module path i have package.json with:

{
  "name": "parallel-nock",
  "version": "0.0.1",
  "description": "Adds a wrapper around nock, which allows to use it more efficiently in parallel tests.",
  "main": "index.js",
  "typings": "index.d.ts",
...
  "dependencies": {
    "bluebird": "^3.3.5",
    "nock": "^8.0.0"
  }
}

index.js is a very simple module, exporting just a function:

'use strict';
var Promise = require('bluebird');
var nock = require('nock');

var scopePromises = {};

function extendScope(Url) {
  return new Promise(function(resolve){
    scope = Object.create(nock(Url));
    scope.release = function() {
      resolve(scope);
    };
  };
}

function parallelNock(Url) {
  var scopePromise = scopePromises[Url];
  if (scopePromise) {
    scopePromise = scopePromise.then((Scope){
      return extendScope;
    });
  } else {
    scopePromise = extendScope(Url);
  }
  scopePromises[Url] = scopePromise;
}

module.exports = parallelNock;

And index.d.ts is:

declare module "parallel-nock" { 
  import nock = require('nock');

  namespace parallelNock {
    export function release():void;
  }

  function parallelNock (host: string, options?: any): any;
  export = parallelNock;
}
  • when I import that module into my project:
import parallelnock = require('parallel-nock');

, I get:

$ tsc
test.ts(4,31): error TS2656: Exported external package typings file '/home/mk/work/4.5.1/workspace2/cloud/node_modules/parallel-nock/index.d.ts' is not a module. Please contact the package author to update the package definition.
@types Docs

Most helpful comment

change your .d.ts file to be a module (i.e. a top level import or export), so it would look like:

import nock = require('nock');

declare namespace parallelNock {
    export function release():void;
}

declare function parallelNock (host: string, options?: any): any;
export = parallelNock;

All 11 comments

change your .d.ts file to be a module (i.e. a top level import or export), so it would look like:

import nock = require('nock');

declare namespace parallelNock {
    export function release():void;
}

declare function parallelNock (host: string, options?: any): any;
export = parallelNock;

we have some documentation about exposing types in npm at: http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html

that could definitely be better though. we are working on updating the typing acquisition story, so i will leave this issue open until that is done.

for completeness, here is the guide for writing definition files: http://www.typescriptlang.org/docs/handbook/writing-declaration-files.html

Oh, thank you for the valuable input, @mhegazy.
Those guides did not help me to get the correct definition file. But I can follow you, so if I got it right, the folder containing the package.json becomes a module, when the .d.ts file, which typings in package.json points to, contains a top level import, which makes it an external module...

About documentation... well, I know, theres always not enough time... Anyway, what you already have is already very valuable.

correct. and the name of the module that users import with is the name of the package. The logic should follow the same node package logic, i.e. index.d.ts would do, otherwise you need to specify "typings" entry, like you do with "main". so your package can look like

- parallelNock
| - package.json 
| - index.js
| - index.d.ts

or

- parallelNock
| - package.json  // "main": ".\lib\index.js", "typings" : ".\lib\index.d.ts"
| - lib
    | - index.js
    | - index.d.ts

I did next:

  1. put index.d.ts for my package into \typings\globals
  2. made update to \typings\index.d.ts:
    /// <reference path="globals/<PackageName>/index.d.ts" />
    and this helped to avoid TS2656 without using top level export.
    Is it correct way?

In case you use typings, you should rather let it do that for you. You can use

typings install file:/path/to/file --save-dev

to add a dependency to a local type definition (refer to typings.json or index.d.ts) or you create a github-repository and fetch it from there.

react markdown use in Typescript.
error: TS2604: JSX element type 'Markdown' does not have any construct or call signatures

import * as Markdown from 'react-markdown';

<Markdown source={this.state.content} skipHtml={true} />
tsconfig.json:

{
  "compilerOptions": {
    "sourceMap": true,
    "module": "es6",
    "target": "es6",
    "lib": [
      "dom",
      "es7"
    ],
    "jsx": "preserve",
    "strict": true,
    "noImplicitAny": true,
    "moduleResolution": "node",
    "baseUrl": "src",
    "keyofStringsOnly": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "typeRoots" : [
      "node_modules/@types/",
      "./typings/markdown.d.ts",
      "./typings/typings.d.ts"
    ]
  },
  "include": [
    "./src/**/*",
    "./typings/markdown.d.ts",
    "./typings/typings.d.ts"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

markdown.d.ts:

declare function Markdown(props: any): any; export = Markdown;

Anyone konws how to resolve it?
Thanks very much!
i don not know why.
@mhegazy

use:

import Markdown from 'react-markdown';

Thank you ,It doesn't report an error,but markdown file doesn't render .
just render blank , not markdown file
@mhegazy

Trying to follow the tips given here, but not quite getting any traction. Thoughts?

https://stackoverflow.com/questions/57032253/providing-an-index-d-ts-file-for-canonical-json

Was this page helpful?
0 / 5 - 0 ratings