What's the proper way to setup a "pure" typescript module

Viewed 2245

I'm trying to build a private module that I know will only be used by another TypeScript project.

According to this (https://github.com/Microsoft/TypeScript/issues/5225) I should be able to simply import my other project without needing to build type definitions.

The problem is I'm missing the type definitions for any dependencies on that library when I try to import it.

Here's the situation:

Lets say you have two projects. lib and app. app imports lib, a pure TypeScript node module.

├── app/
│   ├── dist/
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   └── index.js.map
│   ├── src/
│   │   └── index.ts
│   ├── package.json
│   ├── package-lock.json
│   └── tsconfig.json
└── lib/
    ├── src/
    │   └── index.ts
    ├── package.json
    ├── package-lock.json
    └── tsconfig.json

app simply imports a function from lib and runs it:

import lib from "lib";

lib("test");

Lib imports a dependency and its types, and exports a function:

package.json:

"dependencies": {
  "dotenv": "^6.1.0"
},
"devDependencies": {
  "@types/dotenv": "^4.0.3",
  "typescript": "^3.1.6"
}

app/src/index.ts:

import dotenv from "dotenv";

dotenv.load()

export default (message: string) => {
    console.log(message);
}

When I try to build app I get an error about the missing type definitions from the the lib dependency:

node_modules/lib/src/index.ts:1:20 - error TS7016: Could not find a declaration file for module 'dotenv'. 'lib/node_modules/dotenv/lib/main.js' implicitly has an 'any' type.
  Try `npm install @types/dotenv` if it exists or add a new declaration (.d.ts) file containing `declare module 'dotenv';`

1 import dotenv from "dotenv";

What's the proper way to handle this scenario? It'll work fine in a mixed JS / TS module, because the "compile boundary" will end at the imported module and its exposed types, but since this module is "pure" TypeScript, it'll crawl all of its dependencies as if it were one large repo.

What's the proper way to set this up? Or is the real issue that npm install doesn't install the dev dependencies? Should I install all of the @types as prod dependencies?

2 Answers

According to this: https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

The recommendation is to install all dependencies, as prod dependencies:

Our package exposes declarations from each of those, so any user of our browserify-typescript-extension package needs to have these dependencies as well. For that reason, we used "dependencies" and not "devDependencies", because otherwise our consumers would have needed to manually install those packages. If we had just written a command line application and not expected our package to be used as a library, we might have used devDependencies.

So basically if you are writing a typescript npm module, all dependencies must be prod dependencies.

Yes, in my last experience building typescript npm module, I have to include our 3rd party package typings @type/<package> as dependencies in package.json.

My last npm module was built using ioredis. So my module package.json looks like below:

{
  "name": "my-redis",
  "version": "1.0.0",
  "dependencies": {
    "ioredis": "^4.2.0",
    "@types/ioredis": "^4.0.3"
  },
}

By doing this, if the module is installed in other system, it will automatically can detect the typing, otherwise that system must install the typings package manually.

Related