-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
π Search Terms
skipLibCheck, node_modules, package
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
The TypeScript compiler should be aware of package boundaries, especially when it comes to --noEmit type checks.
Basically anything in node_modules should be "none of its business", at least optionally.
The following options give the impression that this is somehow achievable, when in fact it's not doable at all (or maybe only with yet another tool built to work around compiler limitations):
moduleResolutionresolvePackageJsonExportsresolvePackageJsonImportsskipLibCheckisolatedModulesreferencesin combination withtsc --build --noEmit
Except for browsers, engines these days all support TS in one way or another, and
package managers all support monorepos in one way or another.
During development, there is practically no need (anymore) to compile the source, which would improve DX.
Compilation still is required for browsers, and/or the goal is to reduce shipped code size, or to build a SEA.
However:
Without a compilation step, TSC won't find declaration files and therefore checks source files, treating them as first party code, even if this code is explicitly imported as a third party package (via a specifier that resolves into another package through node_modules, not a relative path that doesn't include node_modules).
Checking of yet uncompiled dependencies in a monorepo will resolve modules from other packages to relative paths / internal dependencies, and therefore a module will be checked as often as it appears as a dependency of a package in the monorepo.
E.g. package a and b depend on c, therefore c will be type checked three times if each package has it's own tsc --noEmit script in its package.json (which it should). That's wasteful, but so is compiling/building dependencies before being able to type check.
Isolated checking of modules and/or packages should be a no-brainer for users. Unfortunately it isn't.
To summarize the feature request:
tsc --noEmit in monorepos should check uncompiled packages only as far as it would with declaration files. The boundary should be the interface imported/used on the call site, without diving deeper into typings of its implementation.
Also note, "monorepo" is mentioned for practical purposes only; what really matters is the package boundary, regardless of monorepo specifics.
The rest are issue references to a subset of those I've read before opening this one, to make sure not to open up an obvious duplicate.
Similar issues, but not focusing on monorepos:
- Feature Request: allow exclusion of node_modules when skipLibCheck is falseΒ #30511
- Disable type checking for node_modules entirelyΒ #40426
- Add an option to ignore type checking for certain filesΒ #52325
Not as closely related, but also highlights on conflicts between tsc and node_modules resolution:
π Motivating Example
import "@scope/module"; // should only be checked on the interface when running `tsc --noEmit`
import "#mapped-to-@scope/module"; // same
// To illustrate the boundary:
export const f = (a: string): number => // signature still matters, if reachable according to api exposed by package.json
a / 2; // implementation inside body: out of scope for packages depending on this export. Yes, this divides a string.π» Use Cases
-
What do you want to use this for?
Type checking packages (or modules) in isolation without compilation. Ideally the fleshed out feature would give you fine grained control over type checker boundaries up to explicit manual definition (think "donut scope" and "globs") in combination with some settings/keywords as presets for well known setups like node packages and npm or pnpm monorepos. The goal is to have as much control over the exits as is given for entries (the latter has
--project,files,include,excludeand other options, the former has none). -
What shortcomings exist with current approaches?
tsc --emitDeclarationOnlyandtsc --noEmitenforce a chronological development hierarchy from dependency to dependent, rather than nonlinear development from interface to implementation across packages. This is not scalable, blocks development and hurts DX, especially in monorepos. -
What workarounds are you using in the meantime?
Not using
tscfor type checking at all. Only use it for type stripping and/or declaration file generation, which will perform type checks as a side effect unless disabled.After some initial discussion: Also
tsc --buildwithreferencesmirroringpackage.jsondependenciesanddevDependenciesfurther minimises full blown builds, at the expense of manual maintenance of error free mirrors.