Set up TypeScript project From Scratch
Tags: typescript, webdev, tutorial, programming
Published: 2022-10-16 16:08:03

## Setting Typescript compiler

**Step 1**: create an empty folder for our project `mkdir typescript-project`

**Step 2**: move into folder `cd typescript-porject`

**Step 3**: initialize the `package.json` with the command: `npm init -y` 

**Step 4**: create `index.ts` file in src folder with the command: `mkdir typescript-project && touch typescript-project/index.js`

**Step 5**: install typescript speedy compiler as dev dependencies with command: `npm i -D @swc/cli @swc/core`

**Step 6**: create configuration file `.swcrc` for `swc` in `typescript-project` folder and add this configuration:

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "dynamicImport": true,
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "target": "es2017",
    "externalHelpers": false,
    "keepClassNames": true,
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    },
    "baseUrl": "src"
  },
  "module": {
    "type": "commonjs"
  }
}
```

**Step 7**: install express `npm i express` and types for express `npm i --save-dev @types/express` and add the below code into `src/index.ts`:
```ts
import express from 'express';
const app = express();

app.get('/', (_req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});
```
**Step 8**: add `build` command under scripts to `package.json` `"build": "swc src -d dist --source-maps"` and start command `
"start": "npm run build && node dist/index.js
`
**Step 9**: test if the app work, by running the command: `npm run start` should print out: `Server started on port 3000`

**Step 10**: running the TypeScript compiler every time you make a change can be tedious. To fix this, install `npm i ts-node-dev` and add `dev` command to `package.json`, command: `"dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts`

`package.json` should look like this:

```json
{
  "name": "setup-project-ts",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "scripts": {
    "start": "npm run build && node dist/index.js",
    "dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts",
    "build": "swc src -d dist --source-maps"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@swc/cli": "^0.1.57",
    "@swc/core": "^1.3.8",
    "@types/express": "^4.17.14",
    "ts-node-dev": "^2.0.0"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}
```

## Setting Eslint + Prettier
- Eslint defines the code conventions
- Prettier performs the auto-formatting based on the ESLint rules

**Step 1**: add needed eslint and prettier dependencies: `npm i eslint eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser --save-dev`

**Step 2**: create `.prettierrc` file in `typescript-project` with content:
```json
{
  "printWidth": 150,
  "tabWidth": 2,
  "singleQuote": true,
  "trailingComma": "all",
  "semi": true,
  "arrowParens": "avoid"
}
```

**Step 3**: add `prettier-format` command to `package.json`: `"prettier-format": "prettier --config .prettierrc  src/**/*.ts --write"`

**Step 4**: test prettier by running: `npm run prettier-format`

**Step 5**: create `.eslintignore` file, with content:
```json
/dist
```

Ignore dist folder when checking code conventions.

**Step 6**: create `.eslintrc` file with content:
```json
{
  "parser": "@typescript-eslint/parser",
  "extends": ["prettier", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "rules": {
    "@typescript-eslint/explicit-member-accessibility": 0,
    "@typescript-eslint/explicit-function-return-type": 0,
    "@typescript-eslint/no-parameter-properties": 0,
    "@typescript-eslint/interface-name-prefix": 0,
    "@typescript-eslint/explicit-module-boundary-types": 0,
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/ban-types": "off",
    "@typescript-eslint/no-var-requires": "off"
  }
}
```
**Step 7**: add `lint` and `lint:fix` command to package.json:
```json
"scripts": {
   "lint": "eslint --ignore-path .gitignore --ext .ts src/",
   "lint:fix": "eslint --ignore-path .gitignore --ext .ts src/ --fix"
}
```
**Step 8**: check if lint is fixing coding conventions by running command: `npm run lint:fix`

`package.json` should look like this:
```json
{
  "name": "setup-project-ts",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "scripts": {
    "start": "npm run build && node dist/index.js",
    "dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts",
    "build": "swc src -d dist --source-maps",
    "lint": "eslint --ignore-path .gitignore --ext .ts src/",
    "lint:fix": "eslint --ignore-path .gitignore --ext .ts src/ --fix",
    "prettier-format": "prettier --config .prettierrc  src/**/*.ts --write"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@swc/cli": "^0.1.57",
    "@swc/core": "^1.3.8",
    "@types/express": "^4.17.14",
    "@typescript-eslint/eslint-plugin": "^5.40.0",
    "@typescript-eslint/parser": "^5.40.0",
    "eslint": "^8.25.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-prettier": "^4.2.1",
    "ts-node-dev": "^2.0.0"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

```

## Pre-commit hooks

**Step 1**: add dependency: `npm run --save-dev pre-commit`

**Step 2**: add `pre-commit` array to your package.json:

```json
{

  "scripts": {
    "start": "npm run build && node dist/index.js",
  },
  "pre-commit": [
    "lint",
    "prettier-format"
  ],
}
```
Before each commit will run `lint` and `prettier-format`.

Code example: https://github.com/DarthRevanXX/typescript-project-example