19.2.0 • Published 8 months ago

@jupiterone/typescript-tools v19.2.0

Weekly downloads
923
License
UNLICENSED
Repository
github
Last release
8 months ago

TypeScript Tools

This Node.js package provides a baseline set of dependencies, configuration, and scripts that can be used by other TypeScript projects.

This Node.js package is opinionated and comes bundled with the following dependencies:

  • typescript

  • prettier

  • jest

  • babel (used by jest and for building/transpiling)

  • eslint

  • husky (allows you specify git hook scripts inside .husky/ directory - read more)

  • lint-staged (used as a precommit hook to automatically reformat changed source files)

  • ttypescript (allows transform plugins to be loaded from tsconfig.json)

Migrating from Husky 4 to Husky 7:

If you've been using previous versions of Husky in your project, the newest version of Husky requires some package maintenance to keep git hooks working (and working better than previously): read more

Helper Scripts

This package provides the following bin entries:

  • check-tsconfig: Fix and, optionally, repair project references in tsconfig.dist.json files. Run yarn check-tsconfig --help for more information.

  • yalc-publish: Use yalc to publish packages locally (better alternative to yarn link) Run yarn yalc-publish --help for more information.

  • yalc-check: Checks package.json files to make sure there are no .yalc entries Run yarn yalc-check --help for more information.

It is recommended that you add helper scripts to projects using @jupiterone/typescript-tools.

For monorepo projects:

{
  "scripts": {
    "tsconfig:repair": "check-tsconfig --monorepo --repair",
    "tsconfig:check": "check-tsconfig --monorepo --no-repair",
    "yalc:publish": "yalc-publish --monorepo",
    "yalc:check": "yalc-check --monorepo"
  }
}

For non-monorepo projects:

{
  "scripts": {
    "tsconfig:repair": "check-tsconfig --repair",
    "tsconfig:check": "check-tsconfig --no-repair",
    "yalc:publish": "yalc-publish",
    "yalc:check": "yalc-check"
  }
}
# Repair project references inside packages/*/tsconfig.dist.json files:
yarn check-tsconfig --monorepo --repair

# Check project references inside packages/*/tsconfig.dist.json files:
yarn check-tsconfig --monorepo

# Publish packages in your monorepo locally using yalc:
yalc-publish --monorepo

# Make sure package.json files do not contain local .yalc dependencies:
yalc-check --monorepo

For more information about yalc, visit:

https://github.com/whitecolor/yalc

Compiling project

For monorepo:

# Update all project references so that they match interproject dependencies:
yarn check-tsconfig --monorepo --repair

# Now compile all packages using project references which allows the
# typescript compiler to compile your packages in the correct order
yarn tspc -b `find ./packages -maxdepth 2 -name tsconfig.dist.json`

For non-monorepo:

# It is recommended to have a tsconfig.dist.json that excludes all test files
# and use that to compile your typescript files
yarn tspc --declaration -p tsconfig.dist.json

Usage: Prettier

Create prettier.config.js at root of your project that contains:

module.exports = require('@jupiterone/typescript-tools/config/prettier');

Create lint-staged.config.js at root of your project that contains:

module.exports = require('@jupiterone/typescript-tools/config/lint-staged');

Also, the following .prettierignore file is recommended:

dist/
work/
node_modules/
coverage/
package.json

If you would like to rewrite ../ style paths in imports to use ~/ then you should modify your project's lint-staged.config.js file.

NOTE: This project also installs prettier-plugin-organize-imports which will automatically be loaded by prettier and it will be used to organize imports.

For monorepo:

// For monorepo
module.exports = {
  '*.{ts,tsx,js,jsx,json,css,md}': [
    'prettier --write',
    'yarn rewrite-imports --monorepo --dir .',
  ],
};

For non-monorepo project:

// For monorepo
module.exports = {
  '*.{ts,tsx,js,jsx,json,css,md}': [
    'prettier --write',
    'yarn rewrite-imports --dir .',
  ],
};

Usage: Jest

Create jest.config.js at root of your project and use the contents below.

For monorepo:

module.exports = {
  ...require('@jupiterone/typescript-tools/config/jest-monorepo'),

  // Optionally, run some setup script before each test script
  setupFilesAfterEnv: ['./jest.setup.ts'],

  collectCoverageFrom: [
    'packages/*/src/**/*.ts',
    '!**/*.test.ts',
    '!**/__tests__/**',
  ],
  coverageThreshold: {
    global: {
      statements: 100,
      branches: 100,
      functions: 100,
      lines: 100,
    },
  },
};

For non-monorepo:

module.exports = {
  ...require('@jupiterone/typescript-tools/config/jest'),

  // Optionally, run some setup script before each test script
  setupFilesAfterEnv: ['./jest.setup.ts'],

  collectCoverage: true,
  collectCoverageFrom: ['src/**/*.ts'],
  coverageThreshold: {
    global: {
      statements: 100,
      branches: 100,
      functions: 100,
      lines: 100,
    },
  },
};

Usage: Babel

Babel is used to convert *.ts files to *.js by stripping away type information. It is used when running jest tests and it can also be used to build files for the web, docker image, serverless function, etc. (when type declaration files are not needed)

Create babel.config.js at root of your project that contains:

module.exports = require('@jupiterone/typescript-tools/config/babel');

For monorepo projects use the following in your root babel.config.js file:

const {
  buildBabelConfig,
} = require('@jupiterone/typescript-tools/config/babel-util');
module.exports = buildBabelConfig({ monorepo: true });

In each of the monorepo packages, use the following in each of your packages/*/.babelrc.js files:

const {
  buildBabelConfig,
} = require('@jupiterone/typescript-tools/config/babel-util');
module.exports = buildBabelConfig({ packageDir: __dirname });

Usage: TypeScript

Create tsconfig.json at root of your project that contains the contents below.

For monorepo:

{
  "extends": "./node_modules/@jupiterone/typescript-tools/config/typescript-node18-monorepo",
  "compilerOptions": {
    "rootDir": ".",
    "outDir": "dist"
  },
  "include": [
    "*.js",
    "*.ts",
    "packages/*/*.js",
    "packages/*/*.ts",
    "packages/*/package.json",
    "packages/*/*/**/*.ts",
    "packages/*/*/**/*.json"
  ],
  "exclude": [
    "packages/*/dist/**/*",
    "packages/*/coverage/**/*",
    "**/bak/**/*",
    "**/*.bak/**/*"
  ]
}

Also, for every monorepo package use this in its ./packages/*/tsconfig.json file:

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": ".",
    "baseUrl": "."
  },
  "include": ["package.json", "**/*.ts", "**/*.json"],
  "exclude": ["dist/**/*", "coverage/**/*", "**/bak/**/*", "**/*.bak/**/*"]
}

Also, for every monorepo package use this in its ./packages/*/tsconfig.dist.json file:

{
  "extends": "./tsconfig.json",
  "exclude": [
    "dist/**/*",
    "coverage/**/*",
    "**/bak/**/*",
    "**/*.bak/**/*",
    "test/**",
    "**/*.test.ts",
    "**/__tests__/**/*.ts",
    "**/__mocks__/**/*.ts"
  ],
  "references": [
    ...
  ]
}

For non-monorepo:

Add this to tsconfig.json file at root of project:

{
  "extends": "./node_modules/@jupiterone/typescript-tools/config/typescript-node18",
  "compilerOptions": {
    "rootDir": ".",
    "baseUrl": ".",
    "outDir": "dist"
  },
  "include": [
    "src/**/*.ts",
    "tools/**/*.ts",
    "tools/*.js",
    "test/**/*.ts",
    "jest.*.ts",
    "jest.*.js",
    "*.config.js"
  ],
  "exclude": ["**/*.bak/**/*", "**/dist/**/*"]
}

Also, for production builds use a tsconfig.dist.json file that excludes tests:

{
  "extends": "./tsconfig.json",
  "include": ["src/**/*.ts"],
  "exclude": ["src/**/*.test.ts"]
}

NOTE: Your config should contain rootDir and baseUrl because these paths need to be relative to your tsconfig.json file and not the TypeScript configuration file that we are extending.

NOTE: You may want to add "skipLibCheck": true to the compilerOptions if you have installed third-party packages that have broken types.

NOTE: TypeScript doesn't use Node module resolution to find tsconfig.json files for extending so we have to use a relative or absolute path. See https://github.com/Microsoft/TypeScript/issues/18865

To perform type-checking:

yarn type-check

NOTE: type-check utility script runs tsc --noEmit.

Usage: ESLint

This package contains eslint configuration for both backend (Node.js) and frontend (React) so pick the configuration that is appropriate for your project.

Regardless of target environment, you can always add .eslintignore to ignore certain files in your project.

The current eslint configuration extends the following:

After extending the configurations above, the following rule overrides are provided by @jupiterone/typescript-tools:

  • @typescript-eslint/explicit-function-return-type": "off"
  • @typescript-eslint/no-explicit-any": "off"
  • @typescript-eslint/no-inferrable-types": "off"
  • @typescript-eslint/no-non-null-assertion": "off"
  • @typescript-eslint/no-require-imports": "off"
  • @typescript-eslint/no-unused-vars": "off"
  • @typescript-eslint/no-use-before-define": "off"
  • @typescript-eslint/no-var-requires": "off"
  • @typescript-eslint/no-unsafe-return": "off"
  • @typescript-eslint/no-unsafe-call": "off"
  • @typescript-eslint/restrict-plus-operands": "off"
  • @typescript-eslint/restrict-template-expressions": "off"
  • @typescript-eslint/no-unsafe-assignment": "off"
  • @typescript-eslint/prefer-string-starts-ends-with": "off"
  • @typescript-eslint/require-await": "off"
  • @typescript-eslint/no-unsafe-member-access": "off"
  • @typescript-eslint/unbound-method": "off"
  • @typescript-eslint/explicit-module-boundary-types": "off"

See https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin for documentation on eslint rules for typescript.

Run eslint using the following command:

yarn eslint --ext .ts,.tsx.js,.jsx .

In your package.json add the following to the scripts section:

"lint": "eslint --ext .ts,.tsx,.js,.jsx ."

IMPORTANT: You currently must explicitly add the --ext argument because eslint will only check .js files by default and you can't control this from the eslint configuration.

ESLint configuration for Node.js

Create .eslintrc at root of your project that contains:

{
  "root": true,
  "extends": ["@jupiterone/eslint-config"],
  "parserOptions": {
    "project": "./tsconfig.json",
    "tsconfigRootDir": "."
  }
}

IMPORTANT: If you are linting *.js files (which are enabled by via --ext argument) then make sure allowJs: true is set in your tsconfig.json, and also make sure the *.js files are included via the include/exclude patterns in your tsconfig.json files. If the typescript compiler does not process the *.js files then you'll see eslint errors similar to the following:

/Development/my-project/my-file.js
  0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: my-file.js.
The file must be included in at least one of the projects provided

ESLint configuration for React

Create .eslintrc at root of your project that contains:

{
  "root": true,
  "extends": ["@jupiterone/eslint-config/react"]
}

Usage: Husky 7

In the updates to Husky for major version 7 they have included some large changes that fix existing Husky problems. (Most of these problems revolved around failing to properly bootstrap a new cloned project with .git/hooks entries and the inability to run hooks without first loading the node.js runtime due to looking in many different places for a JS config that must be added to the .git/hooks directory)

A writeup by the Husky authors can be read here. Summarized major changes for our use-case are as follows:

  • No more .huskyrc and no more [package.json].husky entries. (Husky is configuring Git with shell scripts now, we don't want JS configs)

  • Hooks now live in a directory specified by git config at the core.hooksPath directory

    • Husky will try to set the above path automatically on prepare
  • Maintenance needed to upgrade existing hooks to the new format:

Installation or Upgrade for Previous Projects

  • Instructions to migrate from v4 to v7 automatically

    From the above link:

    yarn add husky@latest --dev \
    && npx husky-init \
    && npm exec -- github:typicode/husky-4-to-7 --remove-v4-config

The above instructions basically just remove the .git/hooks entries, creates a .husky directory, and executes npx husky add .husky/<my-hook> '<My Hook Contents> for each hook in the previous format -- you are free to set up the hooks each on their own, but the aforementioned script will attempt to convert the old format to the Husky 7.x format.

Recommended Hooks

Standard set of Jupiter One hooks are configured as follows, after installing Husky:

npx husky add .husky/pre-commit 'yarn lint-staged && yarn format'
npx husky add .husky/pre-push 'yarn test:ci'

The above pattern can be used to add hooks for any of the supported git-hooks.

19.1.0

8 months ago

19.0.0

9 months ago

19.2.0

8 months ago

18.1.1

9 months ago

17.1.2

9 months ago

17.1.1

9 months ago

18.1.0

1 year ago

18.0.4

1 year ago

18.0.3

1 year ago

18.0.2

1 year ago

18.0.1

1 year ago

18.0.0

1 year ago

17.1.0

1 year ago

17.0.0

2 years ago

16.0.0

2 years ago

15.0.0

3 years ago

14.0.2

3 years ago

14.0.1

3 years ago

14.0.0

3 years ago

13.2.2

3 years ago

13.2.1

3 years ago

13.2.0

3 years ago

13.1.6

3 years ago

13.1.5

3 years ago

13.1.3

3 years ago

13.1.4

3 years ago

13.1.1

3 years ago

13.1.2

3 years ago

13.1.0

3 years ago

13.0.2

3 years ago

13.0.1

3 years ago

13.0.0

3 years ago

12.0.7

4 years ago

12.0.8

4 years ago

12.0.6

4 years ago

12.0.5

4 years ago

12.0.3

4 years ago

12.0.4

4 years ago

12.0.2

4 years ago

12.0.1

4 years ago

12.0.0

4 years ago

11.0.0

4 years ago

10.0.2

4 years ago