# Using Typescript in Vanilla JS projects

So much of Javascript is about tooling these days - and frontend development largely revolves around frameworks such as VueJS or React. It's not always easy to find examples of how to use build tools without complex framework setups. So I'd like to share with you my simple Typescript setup for Vanilla JS projects.

## Setup Overview

In my experimental personal projects l like to keep things simple. They largely consist of a single HTML file, a few Javascript module files, and a stylesheet. There is no need for bundled production builds, pre-processors, post-processors, minifying or any of the other great features that come with modern frontend build tools such as Babel, Webpack or Vite.

What I do value however is Typescript support, and a setup that allows me to easily write and run unit tests. This makes for a smoother developer experience and allows me to use best practice without digging deep into complex tooling.

## Build Tools

For my minimal setup I need two build tools:

- [typescript](https://www.npmjs.com/package/typescript) - for Typescript compilation
- [jest](https://www.npmjs.com/package/jest) - for Jest unit tests

To offer good Typescript support during unit testing I also use these two additional packages:

- [ts-jest](https://www.npmjs.com/package/ts-jest) - allows Jest to test source code written in Typescript
- [@types/jest](https://www.npmjs.com/package/@types/jest) - provides Typescript types for Jest unit tests

Here are the command line arguments to start the project:

```
npm init
npm install -D typescript
npm install -D jest
npm install -D ts-jest
npm install -D @types/jest
```

## Folder Structure

The folder structure for such projects is straightforward:

1. a `dist` folder that holds the final production build (more on this below)
2. a `src` folder that holds the source files
3. a `tests` folder that holds the unit tests
4. the project's root folder holds the package.json files, typescript config files and jest config file

**Folder structure**

![Screenshot 2022-05-13 at 14.00.25.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1652446949271/8itZr9HAo.png align="left")

```
mkdir dist src tests
```

## Typescript Config

The Typescript configuration file is as follows:

**tsconfig.json**

```
{
    "compilerOptions": {
      "target": "ES6",
      "module": "esnext",
      "moduleResolution": "node",
      "noImplicitAny": true,
      "removeComments": true,
      "preserveConstEnums": true,
      "sourceMap": false,
      "outDir": "dist"
    },
    "include": ["src/**/*"]
}
```

The main points to note here are:

1. The `moduleResolution` value ensures that jest modules are correctly resolved.
2. The `outDir` value points to the `dist` folder.

## Jest Config

The Jest configuration file is as follows:

**jest.config.js**

```
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  roots: ["tests"],
  globals: {
    "ts-jest": {
      diagnostics: {
        ignoreCodes: ["TS151001"],
      },
    },
  },
};
```

The main points to note here are:

1. the initial type declaration that pulls types from the `ts-jest` package
2. the `roots` entry that points Jest at the `tests` subfolder
3. the 'diagnostics' entry prevents a warning about potential module import problems

## Package run scripts

The following scripts inside package.json complete the setup:

**package.json**

```
"scripts": {
    "test": "jest",
    "dev": "tsc --watch",
    "build": "tsc"
  }
```

And to get started, just run the `dev` script in your terminal. This will start the Typescript compiler in watch mode, with live recompiles whenever you change your source code.

```
npm run dev
```

## Skeleton HTML and Javascript files

To bring it all together I create a skeleton Javascript file inside the `src` subfolder. This will be the main entry point for the application.

**src/index.ts**

```
console.log("hello world");
```

The Typescript setup means that this file will be compiled into `dist/index.js`.

To use this compiled Javascript file, I include a bare-bones index.html file in the dist folder:

**dist/index.html**

```
<html>
  <head>
    <script type="module" src="./index.js"></script>
  </head>
  <body>
  </body>
</html>
```

The important thing to note here is the `type="module"` identifier. This allows you to use module imports within your index Javascript file. You can separate source code into modules that are easy to maintain and easy to unit test.

In practice in smaller projects I end up with a single module file. It's still worth the extra step to allow unit testing of individual functions within your code.

You can then open the index.html file in your browser. Provided you don't have other external dependencies you won't even need to start a local web server - just start the file under the file protocol.

## Typescript type definitions

So where do Typescript type definitions go in this setup? The simplest way I've found is to create a `types.ts` module file inside the `src` folder. You can then import types from here in your other source code files and your unit tests.

Here is an example file. These interfaces can be imported in the rest of your code and in your unit tests.

**src/types.ts**

```
export interface Person {
  name: string;
  age: number;
}

export interface Settings {
  offset: number;
  margin: number;
}
```

## Whole project setup

Here is an overview of the entire setup.


![Screenshot 2022-05-17 at 14.27.15.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1652794052508/Z7UOT0jg9.png align="left")


1. The `dist` folder contains the skeleton `index.html` file and the compiled JS files
2. The `src` folder contains the `index.js` entry-point JS file, in addition to one or more library module files, and, if you like, a central `types.ts` type definition file
3. The `tests` folder contains jest unit tests


## Conclusion

This is the end of my barebones Javascript setup. I've found it to be strong enough for personal experiments and for smaller commercial projects where a framework is not required.

I'd love to hear your thoughts and feedback. Let me know what your favourite tools are in the comments!









