How to create and publish a TypeScript package.
Tags: javascript, typescript, webdev, npm
Published: 2022-02-06 12:47:55

## Introduction

In this guide, we will build a package for generating currency symbols from their respective 
currency code using typescript and publish it as a **Node.js** package.

This is what we are going to build:
[Currency-symbols-generator NPM](https://www.npmjs.com/package/currency-symbol-generator)
[Github Repo](https://github.com/Anishpras/currency-symbol-generator#readme)

## Alright.Let's get started!
Make sure you have the latest version of node and npm.


```unix
node -v
v16.13.2

npm -v
8.1.2
```

## Pick a great name
This is probably harder than you think. The package name must be Pascal Case and lowercase. With over 1,800,000 packages, do a quick search at https://www.npmjs.com/ to make sure your name isn't used yet. In this guide, we'll choose the name currency-symbol-generator, but make sure to use a **unique name** so you can publish the package, later on, npm 🚀.

## Open you workspace where you want to create your package
In this we will be using our Desktop directory

```
cd Desktop
```

## Let's initialise our Package
We will be using [TSDX](https://tsdx.io/) in this guide as it provides all the necessary dependencies. You can change the name **_currency-symbol-generator_** to your own package name, as it will generate a package.json with the same name.

```
npx tsdx create currency-symbol-generator
```
choose **basic** option when asked in the terminal and press enter.

Then change your directory to the package folder.

```
cd currency-symbol-generator
```
**Note** - Be sure to use the name as specified while creating the package using tsdx.

## Create a git repository
All in order. You need a remote git repository for the package so you can download it. Creating a remote Git repository isn't relevant to this article, but once you've created it, you can use the following lines to initialise your local repository and set up a remote origin.

```
git init
echo "# Currency Symbol Generator" >> README.md
git add . && git commit -m "Initial commit"
git branch -M main
```
Replace <Git Repository Url> with the URL to your remote repository.

```
git remote add origin <Git Repository Url>
git push -u origin main
```
## Modify your package.json
Add **author**, **description**, **keywords**, **repository** and **bugs** key in **_package.json_**.

Your package.json should look like this.

```
{
  "author": "Anish Prashun <anishprashun118@gmail.com",
  "version": "0.1.0",
  "license": "MIT",
  "description": "A minimal package for getting symbol of a currency using the country code.",
  "keywords": [
    "currency",
    "symbol",
    "react",
    "typescript",
    "javascript",
    "currency symbol",
    "get currency symbol",
    "anish prashun"
  ],
  "main": "dist/index.js",
  "typings": "dist/index.d.ts",
  "files": [
    "dist",
    "src"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/Anishpras/currency-symbol-generator",
    "directory": "/"
  },
  "bugs": {
    "url": "https://github.com/Anishpras/currency-symbol-generator/issues"
  },
  "engines": {
    "node": ">=10"
  },
  "scripts": {
    "start": "tsdx watch",
    "build": "tsdx build",
    "test": "tsdx test",
    "lint": "tsdx lint",
    "prepare": "tsdx build",
    "size": "size-limit",
    "analyze": "size-limit --why"
  },
  "peerDependencies": {},
  "husky": {
    "hooks": {
      "pre-commit": "tsdx lint"
    }
  },
  "prettier": {
    "printWidth": 80,
    "semi": true,
    "singleQuote": true,
    "trailingComma": "es5"
  },
  "name": "currency-symbol-generator",
  "module": "dist/currency-symbol-generator.esm.js",
  "size-limit": [
    {
      "path": "dist/currency-symbol-generator.cjs.production.min.js",
      "limit": "10 KB"
    },
    {
      "path": "dist/currency-symbol-generator.esm.js",
      "limit": "10 KB"
    }
  ],
  "devDependencies": {
    "@size-limit/preset-small-lib": "^7.0.5",
    "husky": "^7.0.4",
    "size-limit": "^7.0.5",
    "tsdx": "^0.14.1",
    "tslib": "^2.3.1",
    "typescript": "^4.5.4"
  }
}
```
**Note** - Change the details according to your need, like change the author name to your name and respectively.

## Let's get to the real code now.
Create a **currencyList.ts** under **_src_** folder and create a array that contains all the symbols respective to their currency code.

```
const currencyList = [
  { name: 'AED', symbol: 'د.إ' },
  { name: 'AFN', symbol: '؋' },
  { name: 'ALL', symbol: 'L' },
  { name: 'AMD', symbol: '֏' },
  { name: 'ANG', symbol: 'ƒ' },
  { name: 'AOA', symbol: 'Kz' },
  { name: 'ARS', symbol: '$' },
  { name: 'AUD', symbol: '$' },
  { name: 'AWG', symbol: 'ƒ' },
  { name: 'AZN', symbol: '₼' },
  { name: 'BAM', symbol: 'KM' },
  { name: 'BBD', symbol: '$' },
  { name: 'BDT', symbol: '৳' },
  { name: 'BGN', symbol: 'лв' },
  { name: 'BHD', symbol: '.د.ب' },
  { name: 'BIF', symbol: 'FBu' },
  { name: 'BMD', symbol: '$' },
  { name: 'BND', symbol: '$' },
  { name: 'BOB', symbol: '$b' },
  { name: 'BRL', symbol: 'R$' },
  { name: 'BSD', symbol: '$' },
  { name: 'BTC', symbol: '฿' },
  { name: 'BTN', symbol: 'Nu.' },
  { name: 'BWP', symbol: 'P' },
  { name: 'BYR', symbol: 'Br' },
  { name: 'BYN', symbol: 'Br' },
  { name: 'BZD', symbol: 'BZ$' },
  { name: 'CAD', symbol: '$' },
  { name: 'CDF', symbol: 'FC' },
  { name: 'CHF', symbol: 'CHF' },
  { name: 'CLP', symbol: '$' },
  { name: 'CNY', symbol: '¥' },
  { name: 'COP', symbol: '$' },
  { name: 'CRC', symbol: '₡' },
  { name: 'CUC', symbol: '$' },
  { name: 'CUP', symbol: '₱' },
  { name: 'CVE', symbol: '$' },
  { name: 'CZK', symbol: 'Kč' },
  { name: 'DJF', symbol: 'Fdj' },
  { name: 'DKK', symbol: 'kr' },
  { name: 'DOP', symbol: 'RD$' },
  { name: 'DZD', symbol: 'دج' },
  { name: 'EEK', symbol: 'kr' },
  { name: 'EGP', symbol: '£' },
  { name: 'ERN', symbol: 'Nfk' },
  { name: 'ETB', symbol: 'Br' },
  { name: 'ETH', symbol: 'Ξ' },
  { name: 'EUR', symbol: '€' },
  { name: 'FJD', symbol: '$' },
  { name: 'FKP', symbol: '£' },
  { name: 'GBP', symbol: '£' },
  { name: 'GEL', symbol: '₾' },
  { name: 'GGP', symbol: '£' },
  { name: 'GHC', symbol: '₵' },
  { name: 'GHS', symbol: 'GH₵' },
  { name: 'GIP', symbol: '£' },
  { name: 'GMD', symbol: 'D' },
  { name: 'GNF', symbol: 'FG' },
  { name: 'GTQ', symbol: 'Q' },
  { name: 'GYD', symbol: '$' },
  { name: 'HKD', symbol: '$' },
  { name: 'HNL', symbol: 'L' },
  { name: 'HRK', symbol: 'kn' },
  { name: 'HTG', symbol: 'G' },
  { name: 'HUF', symbol: 'Ft' },
  { name: 'IDR', symbol: 'Rp' },
  { name: 'ILS', symbol: '₪' },
  { name: 'IMP', symbol: '£' },
  { name: 'INR', symbol: '₹' },
  { name: 'IQD', symbol: 'ع.د' },
  { name: 'IRR', symbol: '﷼' },
  { name: 'ISK', symbol: 'kr' },
  { name: 'JEP', symbol: '£' },
  { name: 'JMD', symbol: 'J$' },
  { name: 'JOD', symbol: 'JD' },
  { name: 'JPY', symbol: '¥' },
  { name: 'KES', symbol: 'KSh' },
  { name: 'KGS', symbol: 'лв' },
  { name: 'KHR', symbol: '៛' },
  { name: 'KMF', symbol: 'CF' },
  { name: 'KPW', symbol: '₩' },
  { name: 'KRW', symbol: '₩' },
  { name: 'KWD', symbol: 'KD' },
  { name: 'KYD', symbol: '$' },
  { name: 'KZT', symbol: 'лв' },
  { name: 'LAK', symbol: '₭' },
  { name: 'LBP', symbol: '£' },
  { name: 'LKR', symbol: '₨' },
  { name: 'LRD', symbol: '$' },
  { name: 'LSL', symbol: 'M' },
  { name: 'LTC', symbol: 'Ł' },
  { name: 'LTL', symbol: 'Lt' },
  { name: 'LVL', symbol: 'Ls' },
  { name: 'LYD', symbol: 'LD' },
  { name: 'MAD', symbol: 'MAD' },
  { name: 'MDL', symbol: 'lei' },
  { name: 'MGA', symbol: 'Ar' },
  { name: 'MKD', symbol: 'ден' },
  { name: 'MMK', symbol: 'K' },
  { name: 'MNT', symbol: '₮' },
  { name: 'MOP', symbol: 'MOP$' },
  { name: 'MRO', symbol: 'UM' },
  { name: 'MRU', symbol: 'UM' },
  { name: 'MUR', symbol: '₨' },
  { name: 'MVR', symbol: 'Rf' },
  { name: 'MWK', symbol: 'MK' },
  { name: 'MXN', symbol: '$' },
  { name: 'MYR', symbol: 'RM' },
  { name: 'MZN', symbol: 'MT' },
  { name: 'NAD', symbol: '$' },
  { name: 'NGN', symbol: '₦' },
  { name: 'NIO', symbol: 'C$' },
  { name: 'NOK', symbol: 'kr' },
  { name: 'NPR', symbol: '₨' },
  { name: 'NZD', symbol: '$' },
  { name: 'OMR', symbol: '﷼' },
  { name: 'PAB', symbol: 'B/.' },
  { name: 'PEN', symbol: 'S/.' },
  { name: 'PGK', symbol: 'K' },
  { name: 'PHP', symbol: '₱' },
  { name: 'PKR', symbol: '₨' },
  { name: 'PLN', symbol: 'zł' },
  { name: 'PYG', symbol: 'Gs' },
  { name: 'QAR', symbol: '﷼' },
  { name: 'RMB', symbol: '￥' },
  { name: 'RON', symbol: 'lei' },
  { name: 'RSD', symbol: 'Дин.' },
  { name: 'RUB', symbol: '₽' },
  { name: 'RWF', symbol: 'R₣' },
  { name: 'SAR', symbol: '﷼' },
  { name: 'SBD', symbol: '$' },
  { name: 'SCR', symbol: '₨' },
  { name: 'SDG', symbol: 'ج.س.' },
  { name: 'SEK', symbol: 'kr' },
  { name: 'SGD', symbol: '$' },
  { name: 'SHP', symbol: '£' },
  { name: 'SLL', symbol: 'Le' },
  { name: 'SOS', symbol: 'S' },
  { name: 'SRD', symbol: '$' },
  { name: 'SSP', symbol: '£' },
  { name: 'STD', symbol: 'Db' },
  { name: 'STN', symbol: 'Db' },
  { name: 'SVC', symbol: '$' },
  { name: 'SYP', symbol: '£' },
  { name: 'SZL', symbol: 'E' },
  { name: 'THB', symbol: '฿' },
  { name: 'TJS', symbol: 'SM' },
  { name: 'TMT', symbol: 'T' },
  { name: 'TND', symbol: 'د.ت' },
  { name: 'TOP', symbol: 'T$' },
  { name: 'TRL', symbol: '₤' },
  { name: 'TRY', symbol: '₺' },
  { name: 'TTD', symbol: 'TT$' },
  { name: 'TVD', symbol: '$' },
  { name: 'TWD', symbol: 'NT$' },
  { name: 'TZS', symbol: 'TSh' },
  { name: 'UAH', symbol: '₴' },
  { name: 'UGX', symbol: 'USh' },
  { name: 'USD', symbol: '$' },
  { name: 'UYU', symbol: '$U' },
  { name: 'UZS', symbol: 'лв' },
  { name: 'VEF', symbol: 'Bs' },
  { name: 'VND', symbol: '₫' },
  { name: 'VUV', symbol: 'VT' },
  { name: 'WST', symbol: 'WS$' },
  { name: 'XAF', symbol: 'FCFA' },
  { name: 'XBT', symbol: 'Ƀ' },
  { name: 'XCD', symbol: '$' },
  { name: 'XOF', symbol: 'CFA' },
  { name: 'XPF', symbol: '₣' },
  { name: 'YER', symbol: '﷼' },
  { name: 'ZAR', symbol: 'R' },
  { name: 'ZWD', symbol: 'Z$' },
];

export default currencyList;
```

Now, Open **index.ts** under **_src/index.ts_** from the root.

And change the code from 

```
export const sum = (a: number, b: number) => {
  if ('development' === process.env.NODE_ENV) {
    console.log('boop');
  }
  return a + b;
};
```
to 

```
import currencyList from './currencyList';

export const getCurrencySymbol = (currencyCode: string) => {
  if (
    currencyCode === '' ||
    currencyCode === undefined ||
    currencyCode === null ||
    currencyCode === ' '
  ) {
    console.log('Enter a valid currency code');
  } else {
    for (let i = 0; i < currencyList.length; i++) {
      if (currencyList[i].name === currencyCode) {
        return currencyList[i].symbol;
      }
    }
  }
};

```
Lets understand what are we really doing, we are importing the **currencyList**, then we are exporting a arrow function **_getCurrencySymbol_** which accepts **_currencyCode_** as an argument. 

Then we are checking for null, empty-string, undefined or string with white space in the **_if statement_**. 

Now if the currency code entered is correct then we will use a **_For loop_** for checking against the **_currencyCode_** in our _**currencyList**_ and returning the corresponding symbol.

And thats all for the coding part, Give yourself a pat if you have done this much.

## BONUS 🔥
We are ready for publishing our package but before that we will test it. Yes we will be testing it using jest.

Go to _**test**_ directory and delete all the files, we are pro we will build our own test from scratch. 

Create a **currency.test.ts** file in the **_test_** directory. And write the code.

```
import { getCurrencySymbol } from '../src';

describe('Symbol-Check', () => {
  it('works', () => {
    expect(getCurrencySymbol('INR')).toEqual('₹');
  });
});
```

Here we are checking if our function is working, and for that we have created a test named **_Symbol-Check_** and we are passing _INR_ as our currency code and expecting _₹_ symbol, and if this happens our test will get pass.

Now run 

```
yarn test
```

And you will see a test pass successful message.

## Let's publish our package.

But before it we need to change few configuration in our **_tsconfig.json_**.

Change the _noImplicitReturns_ to _false_ in the **_tsconfig.json_**. Why we are doing it ? You can check this at - [Here](https://www.typescriptlang.org/tsconfig#noImplicitReturns)

Your _**tsconfig.json**_ should look like this-


```
{
  // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
  "include": ["src", "types"],
  "compilerOptions": {
    "module": "esnext",
    "lib": ["dom", "esnext"],
    "importHelpers": true,
    // output .d.ts declaration files for consumers
    "declaration": true,
    // output .js.map sourcemap files for consumers
    "sourceMap": true,
    // match output dir to input dir. e.g. dist/index instead of dist/src/index
    "rootDir": "./src",
    // stricter type-checking for stronger correctness. Recommended by TS
    "strict": true,
    // linter checks for common issues
    "noImplicitReturns": false,
    "noFallthroughCasesInSwitch": true,
    // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    // use Node's module resolution algorithm, instead of the legacy TS one
    "moduleResolution": "node",
    // transpile JSX to React.createElement
    "jsx": "react",
    // interop between ESM and CJS modules. Recommended by TS
    "esModuleInterop": true,
    // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
    "skipLibCheck": true,
    // error out if import and file system have a casing mismatch. Recommended by TS
    "forceConsistentCasingInFileNames": true,
    // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
    "noEmit": true
  }
}
```
Now let's publish our package.

You just need to run one command to publish your package.

```
npm run publish
```

### **🎉 Hurray You just published your typescript package on npm. 🥳**


**Code** - https://github.com/Anishpras/currency-symbol-generator

**Website** - www.anishprashun.com

**LinkedIn** - https://www.linkedin.com/in/anishpras118

**Twitter** - https://twitter.com/APrashun