microsoft / microsoft/TypeScript

Clarify tsconfig extends resolution

Open
#63,109 2 comments 0 reactions 0 assignees View on GitHub
Docs
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

### Acknowledgement

- [x] I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.

### Comment

This is about the contents of [https://www.typescriptlang.org/tsconfig/#extends](https://www.typescriptlang.org/tsconfig/#extends)

This issue doesn't fit a template, but is also not about the website, rather about what behavior to expect from TypeScript tooling and configs. Specifically the field's syntax and how it affects evaluation, which together the title phrases as resolution.

@RyanCavanaugh mentioned such issues can be opened directly in the TypeScript repo [(see comment)](https://github.com/microsoft/TypeScript/issues/62753#issuecomment-3534104209).

I no longer think that updates to `extends` docs wouldn't benefit the reader (as stated once in a [comment](https://github.com/microsoft/TypeScript/issues/62753#issuecomment-3536738103))

I think mentioning Node.js style resolution for the config `extends` field, without clearly explaining how specifiers are resolved leads to misunderstandings of what to expect when using specifiers, starting with recognizing the diff between a path and a specifier.

Reasons being:

- @RyanCavanaugh already mentioned `extends` docs to be outdated in another [comment](https://github.com/microsoft/TypeScript/issues/62753#issuecomment-3529443711)
- #62915 mentions further updates to `extends`
- other tools are considering updates to their implementation to adapt to new features of engines that involve support for `extends` and would probably benefit from up to date documentation ([see esbuild issue 4360](https://github.com/evanw/esbuild/issues/4360))
- previous attempts to align `extends` resolution in tools building on top of TypeScript tackled resolution according to Node.js, rather than using TS config resolution (the latter being undocumented or outdated and potentially misleading), as can be seen in this [VSC pull request](https://github.com/microsoft/vscode/pull/282969) being an attempt to close [a related issue](https://github.com/microsoft/vscode/issues/276592), in which in turn it is mentioned at least once that resolution is not the same and that the docs are unclear or outdated in this regard; also mentioning some of the differences and that resolution should follow compiler behaviour, not some engine unrelated to compiler configs.

I've copied the list of differences I am aware of from one of the linked issues down here below, since they are directly relevant to this issue:

- ts normalizes paths differently than node does (e.g. ts normalizes `\\` path separators [even in specifiers], node doesn't).
- node supports some protocols that tsc doesn't support for `extends` (e.g. in node you can import `node:`, `data:` and `file://`).
- Node has file extension restrictions, tsconfig has not.
- In node only specifiers starting with a dot indicate relative imports, while in tsconfig everything is relative unless it starts with at (@) or hash (#) or syntax indicating a root (I'm only aware of path separators, but maybe there's logic to handle drive letters?) [Edit: this seems not, or no longer, to be the case for `extends`].

Apart from those syntactic differences, it would be worth noting that tsc is largely unaware of packages (support of package/module specifier syntax suggests otherwise).
This has noteworthy implications for monorepos, project boundaries and relative paths in config files. E.g. one could test and answer the following question, but it would be nice if it were documented:

What happens if I extend the config of another package from within a monorepo which has its own `files` or `includes`, without explicitly overriding `files` or `includes`? Will the current (implicit) defaults override the inherited or do I have to be explicit to override inherited entries? It must be the latter, otherwise it would never inherit. For monorepos this means one has to be careful not to include files from other packages (or the opposite, based on what you think would be intuitive), because resolved paths don't resolve to a `node_modules` subpath (that's a guess and may or may not depend on how symlinks are resolved, among other factors). The consequence would be inclusion of other package sources, as well as rendering `skipLibCheck` ineffective.

Edit: Note, when using references and imports in modules, which the previous example did not imply, one gets mixed results according to #62880. Just mentioning this because it would be even more against intuition, if it turns out that references resolve differently from configs. In that other issue the hash-specifiers seem to match what was described before, while the at-specifiers seem to "know" about `node_modules`.

Also not clear from the docs on extends: Does `files` or `includes` override all inherited entries, or only the corresponding field? Following the links for docs on those fields it is not clear how those interact or interfere, neither per config file, nor when it comes to inheritance. Same for `exclude`. Does it affect `include` on a per file basis, or is it inherited as a field that will affect inheriting `includes`? A naive guess would be, fields are inherited independently, but that info is missing.

Search phrase I used to avoid opening a duplicate: "update docs tsconfig extends"

- this is similar to #62753; the difference being, the other claimed buggy behavior, while this is about the lack of documentation or specification
- previous issues about outdated docs led to positive results; example of a successful update: #62705

Contributor guide

Open the contributing guide

Research direction

Start with the tsconfig extends documentation at typescriptlang.org/tsconfig/#extends, then review related issues #62915, #62880, and #62753 for the current behavior and terminology. Clarify specifier resolution and how files, include, and exclude interact across inherited configs, with the documented behavior matching TypeScript tooling.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.