Skip to content

jhmaster2000/nodejs-typescript-template

 
 

Repository files navigation

Modern TypeScript ESM project template

Minimalistic example of configuring TypeScript and Node to:

  • emit modern ES modules code
  • import modules that use Node built-ins
  • import modules that don't have named exports
  • import your own modules without specifying an extension
  • lint with ESLint, with TypeScript support
  • test the TypeScript code instantly without having to build first
  • run the resulting JavaScript code

Bonus: continuous integration script for GitHub Actions. It automatically runs tests on every pushed commit.

Emit ES modules code

In tsconfig.json, set this in compilerOptions:

    "target": "ES2022",
    "module": "ES2022",  // Output `import`/`export` ES modules

Import modules that use Node built-ins (http, url etc.)

  • run npm install --save-dev @types/node
  • in tsconfig.json under compilerOptions, set
    • "moduleResolution": "node", so tsc can find modules when targeting ES6+
    • "types": ["node"] to avoid errors related to Node built-in modules

Import modules that don't have named exports

Normally we could write in TypeScript

import { Foo } from 'package';

but when generating ES modules code, that statement will be passed through as is, and will cause Node to fail with

SyntaxError: The requested module 'package' does not provide an export named 'Foo'

because package doesn't provide named exports.

What we'll do is import the entire module, and then destructure it:

import package from 'package';
const { Foo } = package;

However, this will generate Error TS1192: Module '...' has no default export. To prevent that, set "allowSyntheticDefaultImports": true in tsconfig.json.

Import your own modules without specifying an extension

When transpiling, TypeScript won't generate an extension for you. Run Node with the node --experimental-specifier-resolution=node parameter:

node --experimental-specifier-resolution=node run.js

Otherwise, node mandates that you specify the extension in the import statement.

Run the resulting JavaScript code

Add "type": "module" to package.json, because TypeScript can't generate files with the .mjs extension.

ESLint

To be able to run eslint, we must create an .eslintrc.json file. Then, install the required dependencies:

npm i -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-deprecation eslint-plugin-unicorn

Testing with Mocha

The cleanest way to fully support Mocha with TypeScript, ES Modules and ESLint, is to use ts-node/esm. What we need to do:

  • npm install -D mocha @types/mocha
  • add "mocha" to the types array in tsconfig.json
  • use the .mocharc.jsonc file to config (do not use .js config files).

To run Mocha from package.json, we simply add a "test": "npx mocha" line.

Source maps

If your script generates an error, you'll see the line numbers from the generated .js files, which is not helpful. We want to see the original paths and line numbers from the .ts files. To do that, we'll add sourceMap: true to tsconfig.json, install source-map-support and run node with the -r source-map-support/register parameter. Note that Mocha already takes care of source mapping so you'll see the .ts line numbers without having to do anything extra.

CI testing

Using Travis CI and coveralls, we can configure automatic testing and coverage reporting via .travis.yml configuration file.

About

TypeScript + ESLint + Mocha + C8 project template

Resources

License

Stars

Watchers

Forks

Languages

  • JavaScript 65.8%
  • TypeScript 34.2%