Hello

I'm Alejandro

A Web Engineer from Málaga, Spain based in London, UK

How to create your own Typescript library

Creating my own Typescript library is being my life for the last months, so I wanted share my experience and the steps you should follow to create your very own.

From my point of view, there are a lot of missing points on the Internet when you just want to start writing your code and get that library out. So, I'm going to provide you with a list of five steps you need to follow to create your Typescript library and make your users happy.

1. Setup.

First things first, creating a new project involves setting it up.

Create a new folder and initialize it.

$ mkdir library_name
$ cd library_name
$ npm init -y

This, will create a package.json on your folder that look like this.

{
  "name": "library_name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

I expect you are familiar with those properties, but I'm going to explain you what are them for just in case:

  • name is the name of the library.
  • version is the version the library is currelty at.
  • description is a short description of what the library does.
  • main is the file where users of your library are going to point at when they import it.
  • scripts is a list of tasks we will need to define (More on that later).
  • keywors is a list of words that npm will use to link similar packages.
  • author should be you, so put your name on it.
  • license defines how users will be able to use your library for (comercial purposes...etc.)

2. Install dependencies.

There are three types of dependencies.

  • dependencies, which are used for production code (code that you ship with your library).
  • devDependencies, normally tools you use to make your developer experience better (nothing you ship with your library).
  • peerDepedencies, dependant libraries (Let's say you are using react with hooks at your library. You might want to add a peer dependency on react@>=16.8.0 which introduced hooks to make sure nobody uses your library with a version of react which is less than 16.8.0).

Packages we need to install

  • typescript, the compiler.
  • rollup my choice and recommendation of code bundler for libraries.
  • rollup-plugin-typescript2, this will make sure our code gets compiled to ES5.

Taking into account the concepts about types of dependencies above, where would you put these dependencies under?

In our example, typescript and rollup are tools that makes our development experience better, but you might be building a more complex library. In our case dependencies fall into devDependencies.

$ npm i typescript rollup rollup-plugin-typescript2 --save-dev

3. Write yout library's code.

Enough of the boring, let's write some code.

We are ging to create a folder called src in our root directory and a file called index.ts (Note, this is my choice of folder structure, you can perfectly work with yours).

$ mkdir src
$ cd src
$ touch index.ts

This is going to be a really simple example, because I don't want to focus in the code too much, but to show you how to create your library.

Our library is going to export two functions, sum and deduct. Self explanatory names that will make the code easy to understand.

// index.ts

export function sum(a: number, b: number): number {
  return a + b
}

export function deduct(a: number, b: number): number {
  return a - b
}

4. Configuration.

In this step we need to configure our project to make sure we export our code to our users in the right way.

Typescript

We need a tsconfig.json file that will tell the compiler what are the rules that it needs to follow to compile our code.

{
  "compilerOptions": {
    "outDir": "lib",
    "target": "es5",
    "module": "esnext",
    "lib": ["es2015"],
    "sourceMap": true,
    "strict": true,
    "strictFunctionTypes": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "skipLibCheck": true,
    "declaration": true,
    "esModuleInterop": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "lib", "**/*.test.ts"]
}

Notice, target is es5 in which our code will get compiled to, and we are using es2015, equivalent to ES6 to write our code.

Rollup

To configure rollup, we need a rollup.config.js file in our root folder.

import typescript from 'rollup-plugin-typescript2'

export default [
  {
    input: './src/index.ts',
    output: {
      file: './lib/index.esm.js',
      format: 'esm',
    },
    plugins: [typescript()],
  },
  {
    input: './src/index.ts',
    output: {
      file: './lib/index.js',
      format: 'cjs',
    },
    plugins: [typescript()],
  },
]

We are going to export our code in two different formats, cjs (short of commonjs) and also esm (short of ESModules).

  • CommonJS will allow our users to get all our code, just like any other library.
  • ESModules will allow users to "tree shake" our code, meaning that if they only want to use sum from our library, they are not going to get deduct from it.

package.json

Now, that we have our code, we need to be able to compile and bundle it all together.

We are going to go back a bit on the post and remember the package.json structure. Remember we had scritps which where tasks to run on our code? This is the perfect spot to execute commands to compile our code.

Add a build script.

{
  ...
  "scripts": {
    "build": "rollup -c"
  },
  ...
}

And execute it.

$ npm run build

You should get something like this as output.

> library_name@1.0.0 build /Users/aganglada/dev/library_name
> rollup -c

./src/index.ts → ./lib/index.esm.js...
created ./lib/index.esm.js in 529ms

./src/index.ts → ./lib/index.js...
created ./lib/index.js in 225ms

Now, check your folder structure, where lib appeared with both esm and cjs files, together with index.d.ts, which is our typescript declaration file.

Do you also remember the main property? We said that this will be the entry to our code to our users when they import code from our library. In our case, we are going to add a new property called module which will point to the esm file.

{
  ...
  "main": "lib/index.js",
  "module": "lib/index.esm.js",
  ...
}

Another important thing is, we don't want our users to download our source code, instead we want them to get only our compiled code, so we need to add the files property to our package.json as well, where we will specify only the files that we want to publish.

{
  ...
  "files": [
    "lib",
    "package.json"
  ]
  ...
}

5. And finally, publish

If you don't have an npm account, run

$ npm adduser

and this will automatically create an account on npmjs.com for you.

Otherwise, login with your account using the same command and run

$ npm publish

Your code will be ready to use in seconds!

Conclusion

At the end of this post, I hope you have learned how to create and publish your own library which works with Typescript and it's also "tree shackable" so users don't end up with all your code in their bundles.

Share this post