@jupiterone/typescript-tools
v19.2.0
Published
This Node.js package provides a baseline set of dependencies, configuration, and scripts that can be used by other TypeScript projects.
Downloads
993
Readme
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 byjest
and for building/transpiling)eslint
husky
(allows you specify git hook scripts inside.husky/
directory - read more)lint-staged
(used as aprecommit
hook to automatically reformat changed source files)ttypescript
(allows transform plugins to be loaded fromtsconfig.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 intsconfig.dist.json
files. Runyarn check-tsconfig --help
for more information.yalc-publish
: Useyalc
to publish packages locally (better alternative toyarn link
) Runyarn yalc-publish --help
for more information.yalc-check
: Checkspackage.json
files to make sure there are no.yalc
entries Runyarn 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:
- eslint:recommended: Built-in ecommended
rules for
eslint
. - @typescript-eslint/recommended: Opionated rules that don't require type information.
- @typescript-eslint/recommended-requiring-type-checking:
Opionated rules that use typescript type information (requires
parserOptions.project
ineslint
config). - prettier/@typescript-eslint:
Disables rules that
prettier
will automatically fix.
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 thecore.hooksPath
directory- Husky will try to set the above path automatically on
prepare
- Husky will try to set the above path automatically on
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.