diff --git a/.gitignore b/.gitignore index d54c2ba01..fa309c9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ node_modules/ # TypeScript cache *.tsbuildinfo +**/.tsc-lint-cache/ # Optional npm cache directory .npm diff --git a/eslint.config.mjs b/eslint.config.mjs index 1739e1dce..ca3a45bd7 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -11,7 +11,13 @@ const tsconfigRootDir = path.dirname(fileURLToPath(import.meta.url)); const config = createConfig([ ...base, { - ignores: ['coverage/**', 'dist/**', 'docs/**', '.yarn/**'], + ignores: [ + '**/.tsc-lint-cache', + 'coverage/**', + 'dist/**', + 'docs/**', + '.yarn/**', + ], }, { linterOptions: { diff --git a/package.json b/package.json index 4a8ac0332..b61152fd4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "build:clean": "yarn build:only-clean && yarn build", "build:docs": "typedoc", "build:only-clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo", - "lint": "yarn lint:eslint && yarn lint:constraints && yarn lint:misc --check && yarn lint:dependencies && yarn lint:changelog", + "lint": "yarn lint:tsc && yarn lint:eslint && yarn lint:constraints && yarn lint:misc --check && yarn lint:dependencies && yarn lint:changelog", "lint:changelog": "auto-changelog validate --prettier", "lint:constraints": "yarn constraints", "lint:dependencies": "knip --config knip.config.mts --dependencies && yarn dedupe --check", @@ -45,6 +45,7 @@ "lint:eslint": "eslint . --cache", "lint:fix": "yarn lint:eslint --fix && yarn lint:constraints --fix && yarn lint:misc --write && yarn lint:dependencies:fix && yarn lint:changelog", "lint:misc": "oxfmt --ignore-path .gitignore", + "lint:tsc": "tsc --project tsconfig.lint.json", "prepack": "./scripts/prepack.sh", "test": "yarn test:source && yarn test:types", "test:source": "jest && jest-it-up --config jest.config.cjs", diff --git a/tsconfig.lint.json b/tsconfig.lint.json new file mode 100644 index 000000000..a4cf1e123 --- /dev/null +++ b/tsconfig.lint.json @@ -0,0 +1,37 @@ +{ + /** + * Type checks everything the build does not: tests, fixtures and the config + * files at the root. `tsconfig.build.json` only covers `src` minus tests, and + * ts-jest runs in transpile-only mode because `isolatedModules` is set, so + * without this nothing checks the types in a test file. + */ + "extends": "./tsconfig.json", + "compilerOptions": { + /** + * Dependencies ship declarations that do not satisfy the strict flags used + * here, and their errors are not ours to fix. + */ + "skipLibCheck": true, + /** + * Emit into a hidden, git ignored cache directory, matching how `lint:tsc` + * works in core. Emitting is what makes `tsBuildInfoFile` meaningful, so + * repeat runs only check what changed. Only declarations are written, since + * the JavaScript would be thrown away. `tsconfig.json` sets `noEmit` for the + * editor and `tsconfig.build.json` owns the real build, so both are + * overridden here rather than the other way round. + */ + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "incremental": true, + "outDir": "./.tsc-lint-cache", + "tsBuildInfoFile": "./.tsc-lint-cache/tsconfig.tsbuildinfo" + }, + /** + * `*.test-d.ts` files belong to `tsd`, which type checks them itself via + * `yarn test:types`. Pulling them in here would drag `tsd`'s own types into + * the program, and those reference `lib="esnext"`, which widens built in + * types like `ReadonlySet` well beyond the `lib` this package targets. + */ + "exclude": ["./dist/**/*", "./src/**/*.test-d.ts"] +}