How to Start a TypeScript Project from Scratch

2023-03-24技术相关

This article summaries my practices of how to start a TypeScript project from scratch, including the configurations of code style, code lint, and commit lint.

All the following steps are performed using pnpm and VSCode.

1. TypeScript

First things first, we need to install TypeScript and configure tsconfig.json.

pnpm tsc --init # create tsconfig.json

Normally the default configuration is good enough. But we can tweak some of them to make our coding more convenient.

First, set our rootDir and outDir:

{
    "rootDir": "./src",
    "outDir": "./dist"
}

Second, set baseUrl and paths to enable absolute module lookup:

{
    "baseUrl": "./src",                                
    "paths": {
      "@/*": ["./*"]
    }
}

Why? Imagine that we have a configuration file config.ts at the root of the project, and lots of modules import it. If a module file someModule.ts is deeply nested relative to config.ts, the import path is like ../../../../../config.ts, which is nasty. Making things worse, if someModule.ts is moved to a different path, all the relative import paths may not work anymore. With absolute module lookup, the import path can be @/config.ts, and it’s always valid unless you moved config.ts. Pretty neat, right?

The TypeScript compiler knows about the configuration and can provide correct type checking. However, after compiling, Node.js does not aware of the mapping. Additionally, we need tsc-alias to solve this.

2. Prettier

We can use Prettier to ensure our code style. Follow the document to install and configure it.

Here are some additional suggestions.

  1. For simplicity, don't create .prettierrc.json. Instead, we put the configurations in package.json.
  2. We don't need .prettierignore. We can limit Prettier to format certain files by using lint-staged.
// package.json
{
  "lint-staged": {
    "src/**/*.(j|t)(s|sx)": "prettier --write --ignore-unknown"
  }
}

If you are migrating from an existing project, you can use the following command to format your current codes:

pnpm prettier --write --ignore-unknown src/

3. ESLint

We use ESLint to avoid frequent problems. Follow the document to install and configure it.

Here are some additional suggestions.

  1. Again, don't create .eslintrc.json, put the configuration in package.json.
  2. Follow the instructions of Prettier document to avoid conflicts between ESLint and Prettier.

After the installation, remember to modify the configuration of lint-staged:

// package.json
{
  "lint-staged": {
        "src/**/*.(j|t)(s|sx)": [
            "eslint --fix",
            "prettier --write --ignore-unknown"
        ]
    }
}

Some extra configurations for TypeScript, see the document of typescript-eslint.

{
    "eslintConfig": {
        "parserOptions": {
            "project": true
        }
    }
}

If you want to sort imports, the simple-import-sort plugin is easier to use compared with the integrated rule of ESLint.

If you are migrating from an existing project, you can use the following command to lint your current codes:

pnpm eslint --fix src/

4. Commit Lint

commitlint is used for making the format of our commit messages consistent. Follow the document to install and configure it.

5. Jest Configuration

We need ts-jest to make Jest work with TypeScript. See the document of Jest and ts-jest.

6. package.json Scripts

We can add some scripts in package.json for convince:

// package.json
{
    "scripts": {
        "watch": "tsc --watch",
        "build": "tsc",
        "test": "jest -o --passWithNoTests"
    }
}

By the way, the npm script of husky introduces error when you install dependencies with pnpm i -P. We can replace it to avoid the error:

// package.json
{
    "scripts": {
        "prepare": "test -d node_modules/husky && husky install || echo \"husky is not installed\""
    }
}