Writing npm modules in TypeScript
Javascriptnode.jsNpmTypescriptJavascript Problem Overview
I am working on my first npm module. I briefly worked with TypeScript before and a big problem was that for many modules there were no definition files available. So I thought it would be a good idea to write my module in TypeScript.
However, I can't find any information on the best way to do that. I found this related question "Can I write npm package in CoffeeScript?" where people suggest only publishing the JavaScript files. But in contrast to the CoffeeScript files, the TypeScript files might actually be useful if they are used within a TypeScript application.
Should I include TypeScript files when publishing an npm module, or should I only publish the JavaScript files and provide the generated .d.ts files to DefinitelyTyped?
Javascript Solutions
Solution 1 - Javascript
Here is a sample Node module written in TypeScript : https://github.com/basarat/ts-npm-module
Here is a sample TypeScript project that uses this sample module https://github.com/basarat/ts-npm-module-consume
Basically you need to :
- compile with
commonjs
anddeclaration:true
- generate a
.d.ts
file
And then
- Have your ide read the generated
.d.ts
.
Atom-TypeScript just provides a nice workflow around this : https://github.com/TypeStrong/atom-typescript#packagejson-support
Solution 2 - Javascript
With TypeScript 4.x, TypeScript 3.x or TypeScript 2.x, the following steps describe what you have to do to create a library (npm package) with TypeScript:
- Create your project as you normally would (with tests and everything)
- Add
declaration: true
totsconfig.json
to generate typings. - Export the API through an
index.ts
- In the
package.json
, point to your generated typings. For example if youroutDir
isdist
, then add"types": "dist/index.d.ts"
to your package json. - In the
package.json
, point to your main entry file. For example if youroutDir
isdist
and the main entry file isindex.js
, then add"main": "dist/index.js"
to your package.json. - In the
package.json
, whitelist the files you'd like to ship to npm:files: ["/dist"]
. An alternative approach is blacklisting with.npmignore
, but it's harder to keep up to date. - Publish to npm with
npm publish
. Use semver specifications for updates (patch / bug fixnpm version patch
, non-breaking additionsnpm version minor
, breaking api changesnpm version major
)
Since it got me a while to sift through all the outdated resources on this topic on the internet (like the one on this page...) I decided to wrap it up in how-to-write-a-typescript-library with an up-to-date working minimal example.
Solution 3 - Javascript
This is a more recent answer using TypeScript 1.8.10:
My project structure is:
|
|--- src
|--- test
|--- dist <= My gulp file compiles and places the js, sourcemaps and .d.ts files here
| |--- src
| |--- test
|--- typings
.gitignore
.npmignore
gulpfile.js
package.json
README.md
tsconfig.json
tslint.json
typings.json
I added the following in .npmignore
to avoid including extraneous files and keep the bare minimum to have the package imported and working:
node_modules/
*.log
*.tgz
src/
test/
gulpfile.js
tsconfig.json
tslint.json
typings.json
typings
dist/test
My .gitignore
has:
typings
# ignore .js.map files
*.js.map
*.js
dist
My package.json
has:
"main": "dist/src/index.js",
"typings": "dist/src/index.d.ts",
Now I run:
npm pack
The resultant file (when unzipped) has the following structure:
|
|--- dist
| |--- src
| |
| index.js
| index.js.map
| index.d.ts
|
package.json
README.md
Now I go to the project where I want to use this as a library and type:
npm install ./project-1.0.0.tgz
It successfully installs.
Now I create a file index.ts
in my project where I just installed the npm
import Project = require("project");
Typing Project.
gives me the Intellisense options which was the point of this whole exercise.
Hope this helps someone else in using their TypeScript npm projects as internal libraries in their bigger projects.
PS: I believe that this approach of compiling projects to npm modules which can be used in other projects is reminiscent of the .dll
in the .NET
world. I could well imagine projects being organised in a Solution in VS Code where each project produces a an npm package which can then be used in another project in the solution as a dependency.
Since it took a fair amount of time for me to figure this out, I have posted it in case someone is stuck here.
I also posted it for a closed bug at: https://github.com/npm/npm/issues/11546
This example has been uploaded to Github: vchatterji/tsc-seed
Solution 4 - Javascript
You should publish the original typescript sources instead of the type definition. In package.json
let the 'types' property point to the *.ts file.
*.d.ts
are good to annotate existing JS libs, but as a consumer I'd rather read the typescript code than switching between type definitions and down-leveled, generated JS code.
Solution 5 - Javascript
I mainly follow the suggestion by Varun Chatterji
But, I would like to show a complete example with unit testing and code coverage and publishing it into npm
and importing them using javascript
or typescript
This module is written using typescript 2.2
and it is important to configure the prepublish
hook to compile the code using tsc
before publish it to npm
Solution 6 - Javascript
You can use autodts to handle distributing and using .d.ts
files from npm also without support from the Atom IDE.
autodts generate
will bundle all your own .d.ts
files together for publishing on npm, and autodts link
handles references to other installed packages, which may not always be directly under node_modules
in a larger project split into several subpackages.
Both commands read their settings from package.json
and tsconfig.json
in "convention over configuration" style.
There's another answer on stackoverflow and a blog post with more details.