Skip to content

Instantly share code, notes, and snippets.

@AlexMoffat
Last active July 9, 2023 02:13
Show Gist options
  • Save AlexMoffat/aede46d7cf66d87f924020298df08e5b to your computer and use it in GitHub Desktop.
Save AlexMoffat/aede46d7cf66d87f924020298df08e5b to your computer and use it in GitHub Desktop.
Instructions for creating a basic TypeScript project from scratch

Setting up a TypeScript project from scratch on OS X. All TypeScript source will be under a src directory.

nvm and node

Install nvm globally. Follow the instructions from the nvm github readme.

Create the project directory and cd into it.

Use nvm to install and choose the version of node. Here we'll use version 18.

nvm install 18 nvm use 18

Create .nvmrc file to record the node version to use for the project. After this is created nvm use will switch to the version in the .nvmrc file and nvm install will install that version if not already available.

echo $(nvm current) > .nvmrc

yarn

Enable corepack in node.

corepack enable

Update global yarn version

corepack prepare yarn@stable --activate

Set the version of yarn to use locally. This will create the package.json file with just the packageManager property and create .yarnrc.yml to provide the path to the version of yarn to use.

yarn set version stable

Add engines to package.json.

"engines": {
    "node": "^18.6.0",
    "npm": "^9.6.7"
  }

Set the name, author, license and version properties in package.json. Create an appropriate LICENSE file.

TypeScript

Add TypeScript as a dev dependency.

yarn add --dev typescript

Add base configuration for typescript to use in tsconfig.json as a dev dependency.

yarn add --dev @tsconfig/node18

Create the tsconfig.json file.

{
	// Modifications to the default values and values provided in in the "@tsconfig/node18/tsconfig"
	// configuration.
    "compilerOptions": {
		// https://www.typescriptlang.org/tsconfig#composite enforces constraints that
		// make it easier for build tools to determine if a project has already been built
        "composite": true,
		// https://www.typescriptlang.org/tsconfig#outDir - destination for compiled files
        "outDir": "dist",
		// https://www.typescriptlang.org/tsconfig#noFallthroughCasesInSwitch - default is false
        "noFallthroughCasesInSwitch": true,
		// https://www.typescriptlang.org/tsconfig#noImplicitReturns - default is false
        "noImplicitReturns": true,
		// https://www.typescriptlang.org/tsconfig#noUnusedLocals - default is false
        "noUnusedParameters": true,
		// https://www.typescriptlang.org/tsconfig#sourceMap - generate source maps
        "sourceMap": true,
    },
    "extends": "@tsconfig/node18/tsconfig",
    "include": ["src/**/*.ts"]
}

Add the types for node as a dev dependency.

yarn add --dev @types/node

Add script to type check code to package.json so that yarn type runs tsc.

"type": "tsc"

eslint and prettier

Add eslint as a dev dependency.

yarn add --dev eslint

Add support for typescript to eslint. A dev dependency.

yarn add --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin

Add prettier and the config to use prettier with eslint.

yarn add --dev prettier yarn add --dev eslint-config-prettier yarn add --dev eslint-plugin-prettier

Note: 2023-07-08 If you end up with "prettier": "^3.0.0" in package.json you'll need "eslint-plugin-prettier": "^5.0.0-alpha.1" to prevent TypeError: prettier.resolveConfig.sync is not a function.

Create .prettierignore and .prettierrc.yml

.idea
.vscode
.yarn
build
dist
# Only the values that differ from the defaults.
# I think 80 leads to lines that are too short.
printWidth: 100
# https://prettier.io/docs/en/options.html#quotes
singleQuote: true
# https://prettier.io/docs/en/options.html#trailing-commas
trailingComma: "all"

Create .eslintrc.json to configure eslint

{
  "root": true,
  // Parser to use because we're linting TypeScript
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": [
      "./tsconfig.json"
    ]
  },
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    // See https://eslint.org/docs/rules/ for the rules that are enabled by this configuration.
    "eslint:recommended",
    // See https://typescript-eslint.io/getting-started and 
    // https://typescript-eslint.io/linting/typed-linting. These configurations set up the
    // recommended eslint config for linting typescript.
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    // See https://github.com/prettier/eslint-plugin-prettier#recommended-configuration. This
    // sets up the prettier plugin and the recommended eslint config for prettier.
    "plugin:prettier/recommended"
  ],
  "ignorePatterns": [
    ".idea/**",
    ".yarn/**",
    "build/**",
    "cdk.out/**",
    "coverage/**",
    "dist/**",
    "jest.config.js",
    "node_modules/**",
    "webpack.config.js"
  ]
}

Add scripts to run linting and formatting to package.json. yarn lint to lint with eslint and yarn format to format with prettier.

"format": "prettier --write --config .prettierrc.yml 'src/**/*.ts'",
"lint": "eslint ."

vscode

Setup vscode. This will add .yarn/sdks and .vscode directories.

yarn dlx @yarnpkg/sdks vscode

jest

Add jest and its type definitions.

yarn add --dev jest @jest/globals

Use swc to speed up test execution.

yarn add --dev @swc/core @swc/jest

Create jest.config.js. Don't use typescript for the configuration file because that needs ts-node and we're not using that for anything else so it's a waste to use it for the tests

yarn run jest --init

The following questions will help Jest to create a suitable configuration for your project

✔ Would you like to use Typescript for the configuration file? … no
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › v8
✔ Automatically clear mock calls, instances, contexts and results before every test? … no

Modify jest.config.js to

  1. edit testMatch property so that tests are only found in the src/test directory. This is so the compiled code in dist is not scanned.
  2. edit transform property to use swc to run tests.
  testMatch: [
    "<rootDir>/src/test/**/*.test.ts"
  ],
  transform: {
    "^.+\\.(t|j)sx?$": "@swc/jest",
  }

Add the jest extension to vscode and set the rootPath setting to src/test.

Add script to run the tests to package.json so that yarn test runs jest.

"test": "jest"

Sanity check

Create a src/main/helloWorld.ts file and corresponding test src/test/helloWorld.test.ts.

helloWorld.ts

function helloWorld(): string {
    return 'hello world';
};

export { helloWorld };

helloWorld.test.ts

import { describe, expect, test } from "@jest/globals";
import { helloWorld } from "../main/helloWorld";

describe('helloWorld module', () => {
    test('returns hello world', () => {
        const result = helloWorld();
        expect(result).toEqual('hello world');
    });
});

Run yarn type and yarn test to make sure everything is working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment