Writing npm modules in TypeScript

36,240

Solution 1

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 and declaration: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

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 to tsconfig.json to generate typings.
  • Export the API through an index.ts
  • In the package.json, point to your generated typings. For example if your outDir is dist, then add "types": "dist/index.d.ts" to your package json.
  • In the package.json, point to your main entry file. For example if your outDir is dist and the main entry file is index.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 fix npm version patch, non-breaking additions npm version minor, breaking api changes npm 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

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

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

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

https://github.com/sweetim/haversine-position

https://www.npmjs.com/package/haversine-position

Share:
36,240

Related videos on Youtube

Andreas Gassmann
Author by

Andreas Gassmann

Updated on March 10, 2021

Comments

  • Andreas Gassmann
    Andreas Gassmann about 3 years

    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?

    • styfle
      styfle over 6 years
      Helpful Notes: I wrote the project, copee, along with a blog post to walk you through setting up a TS project to emit type definitions along with CJS and ESM targets before publishing to npm. This will maximize usage with node.js and browsers going forward.
  • Fidan Hakaj
    Fidan Hakaj over 8 years
    Atom-TypeScript anchor link needs to be updated (anchor not valid anymore).
  • justin
    justin almost 8 years
    @basarat, in ts-npm-module you're using "version": "1.5.0-alpha". I assume this is the version of Typescript you're transpiling with. Does it matter to leave this out? (it's not done automatically by the Atom plugin). If a version is used, will this require other users to use the exact version to transpile (or only newer ones)? (or maybe it's the version of tsconfig.json?)
  • Admin
    Admin almost 8 years
    Do you have any use case with modules depending on other libraries? To avoid the duplicate definition problem you need to configure tsconfig.json, but this seems too manual in my opinion.
  • Han Che
    Han Che over 7 years
    could you upload an example on github? That would help a lot! :)
  • Varun Chatterji
    Varun Chatterji over 7 years
    Example has been uploaded to Github: github.com/vchatterji/tsc-seed
  • SuperUberDuper
    SuperUberDuper over 7 years
    would you still advocate this approach in q4 2016?
  • SuperUberDuper
    SuperUberDuper over 7 years
    How can it also be used in non typescript projects?
  • Jas
    Jas over 7 years
    can i then use this typescript module from javascript?
  • Sven Efftinge
    Sven Efftinge about 7 years
    The TypeScript compiler seems to be not fit for that so far. See this issue github.com/Microsoft/TypeScript/issues/14479
  • JJWesterkamp
    JJWesterkamp about 7 years
    That's a very useful example, thanks for sharing! I'm currently also trying to get the hang of creating packages in this fashion.
  • Tim
    Tim about 7 years
    currently including *.d.ts is the recommended way to do so, though i agree with you the benefits to include *.ts files,typescriptlang.org/docs/handbook/declaration-files/…
  • adgang
    adgang almost 7 years
    As of July 2017, this is the best project structure I have come across. Thanks to Tim and Varun Chatterji
  • chrismarx
    chrismarx almost 7 years
  • Olian04
    Olian04 over 6 years
    Will i have to check the js in to source control? Or does npm keep its own version of the code?
  • Purag
    Purag over 6 years
    @Olian04 You tell create an .npmignore file to tell npm which files to ignore when publishing (the .ts files) and a .gitignore to tell git which files to ignore (dist/)
  • Josh M.
    Josh M. over 5 years
    @Olian04 no, you do not need to (and IMO shouldn't) commit the generated JS file/s. Those are not part of the project's source.