Automatic Type Acquisition (ATA) is the subsystem in tsserver that automatically discovers and installs @types packages for JavaScript projects that lack TypeScript type information. This page documents the ATA architecture: the TypingsInstaller process, the discoverTypings inference logic, the SafeList/TypesMap safety mechanisms, the global typings cache, and how tsserver communicates with the installer.
For background on how tsserver manages projects that ATA attaches to, see Project Management. For the tsserver protocol at large, see tsserver Protocol.
ATA runs as a separate child process (typingsInstaller.js) spawned by tsserver. The two sides communicate over a Node.js IPC channel using a structured message protocol.
Architecture Diagram: ATA Process Boundary
Sources: src/tsserver/nodeServer.ts392-476 src/typingsInstallerCore/typingsInstaller.ts116-237 src/typingsInstaller/nodeTypingsInstaller.ts84-187
| Component | File | Role |
|---|---|---|
TypingsInstaller | src/typingsInstallerCore/typingsInstaller.ts | Abstract base class; orchestrates discovery, caching, and install |
NodeTypingsInstaller | src/typingsInstaller/nodeTypingsInstaller.ts | Concrete implementation; runs npm via execSync |
NodeTypingsInstallerAdapter | src/tsserver/nodeServer.ts | Tsserver-side bridge; spawns child process, relays messages |
discoverTypings() | src/jsTyping/jsTyping.ts | Infers required @types packages from project files |
loadSafeList() | src/jsTyping/jsTyping.ts | Loads filename-to-package mapping from typingSafeList.json |
loadTypesMap() | src/jsTyping/jsTyping.ts | Loads simpleMap from typesMap.json (preferred over SafeList) |
installNpmPackages() | src/typingsInstallerCore/typingsInstaller.ts | Builds and runs the npm install command |
Arguments namespace | src/jsTyping/shared.ts | CLI argument name constants for the installer process |
The two sides of ATA exchange typed messages over IPC. All message kinds are defined as string literal types in src/jsTyping/shared.ts and src/jsTyping/types.ts.
Diagram: ATA Message Flow
Sources: src/jsTyping/shared.ts1-60 src/jsTyping/types.ts20-90 src/typingsInstallerCore/typingsInstaller.ts145-169
| Type | kind field | Description |
|---|---|---|
DiscoverTypings | "discover" | Triggers typing inference for a project |
CloseProject | "closeProject" | Cleans up watchers for a closed project |
TypesRegistryRequest | "typesRegistry" | Requests the full types registry map |
InstallPackageRequest | "installPackage" | Installs a specific package on user request |
| Constant | Kind string | Description |
|---|---|---|
ActionSet | "action::set" | Provides resolved typing file paths to use |
ActionInvalidate | "action::invalidate" | Tells tsserver to invalidate cached typings |
ActionPackageInstalled | "action::packageInstalled" | Result of an InstallPackageRequest |
EventTypesRegistry | "event::typesRegistry" | Full types registry contents |
EventBeginInstallTypes | "event::beginInstallTypes" | Install started (for telemetry/UI) |
EventEndInstallTypes | "event::endInstallTypes" | Install finished |
EventInitializationFailed | "event::initializationFailed" | Installer startup error |
ActionWatchTypingLocations | "action::watchTypingLocations" | Paths tsserver should watch for changes |
discoverTypings() — Inference LogicdiscoverTypings() in src/jsTyping/jsTyping.ts104-200 is the core function that determines which @types packages a project needs. It returns:
cachedTypingPaths — already-installed typings ready to usenewTypingNames — packages that need to be installedfilesToWatch — paths to watch for future changes (e.g., package.json)Diagram: discoverTypings() Inference Pipeline
Sources: src/jsTyping/jsTyping.ts104-200
The SafeList is a ReadonlyMap<string, string> that maps filename patterns to npm @types package names. For example, a file named jquery.js maps to "jquery", triggering installation of @types/jquery.
loadTypesMap() — reads the simpleMap section from typesMap.json (preferred)loadSafeList() — reads key-value pairs from typingSafeList.json (fallback)The installer prefers typesMap.json over typingSafeList.json:
typesMap.json (simpleMap) ← preferred
typingSafeList.json ← fallback
Both are located in the TypeScript lib directory by default but can be overridden with the --typesMapLocation and --typingSafeListLocation CLI arguments.
Sources: src/jsTyping/jsTyping.ts76-91 src/typingsInstallerCore/typingsInstaller.ts274-286
discoverTypings() walks the directories of all project .js/.jsx files and the project root, searching for package.json and bower.json. It reads dependencies, devDependencies, peerDependencies, and optionalDependencies and adds those package names to the inferred typings set.
Node.js built-in module names (from nodeCoreModules) are normalized to "node", so any reference to fs, path, http, etc. triggers @types/node.
Sources: src/jsTyping/jsTyping.ts137-144 src/jsTyping/jsTyping.ts67-69
TypingsInstaller — Abstract Base ClassTypingsInstaller (src/typingsInstallerCore/typingsInstaller.ts116-400) manages the full install lifecycle. Subclasses implement two abstract methods:
| Abstract Method | Purpose |
|---|---|
installWorker(requestId, packageNames, cwd, onRequestCompleted) | Executes the actual npm install command |
sendResponse(response) | Sends a response back to tsserver |
typesRegistry (abstract property) | The loaded types registry map |
Key internal state:
| Field | Type | Purpose |
|---|---|---|
packageNameToTypingLocation | Map<string, JsTyping.CachedTyping> | Caches already-resolved typing paths and versions |
missingTypingsSet | Set<string> | Packages known not to exist in the registry |
knownCachesSet | Set<string> | Directories already scanned for cached typings |
projectWatchers | Map<string, Set<string>> | Per-project file paths being watched |
safeList | JsTyping.SafeList | undefined | Lazily loaded filename→package map |
pendingRunRequests | PendingRequest[] | Queue for throttled installs |
throttleLimit | number | Max concurrent npm install runs |
On construction and on each DiscoverTypings request (when a cachePath is provided), processCacheLocation() reads package.json and package-lock.json from the cache directory. It populates packageNameToTypingLocation with already-installed @types packages, so future requests can return cached paths immediately without reinstalling.
Sources: src/typingsInstallerCore/typingsInstaller.ts288-350
TypingsInstaller limits concurrent npm installs via throttleLimit. New installs are queued in pendingRunRequests. When a running install completes, onRequestCompleted() is called, which dequeues and starts the next pending request.
NodeTypingsInstallerAdapter in tsserver sets its own limit of maxActiveRequestCount = 10 on the number of pending messages it will queue before stalling.
Sources: src/typingsInstallerCore/typingsInstaller.ts363-400 src/tsserver/nodeServer.ts399-400
NodeTypingsInstaller — Node.js ImplementationNodeTypingsInstaller (src/typingsInstaller/nodeTypingsInstaller.ts84-187) is the concrete installer that runs as typingsInstaller.js.
Startup sequence:
Arguments namespace in src/jsTyping/shared.ts)ensurePackageDirectoryExists(globalTypingsCacheLocation) to set up the cache directorynpm install --ignore-scripts types-registry@<latestDistTag> to get a fresh list of available @types packagesnode_modules/types-registry/index.json via loadTypesRegistryFile()process.on("message", ...) loop to handle incoming requestsinstallWorker() implementation:
Calls installNpmPackages(), which constructs and runs an npm install command of the form:
npm install --ignore-scripts @types/pkg1 @types/pkg2 ... --save-dev --user-agent="typesInstaller/<tsVersion>"
Commands are split into chunks to stay under 8000 characters (command-line limit).
sendResponse() implementation:
Calls process.send!(response) to send the response back over the IPC channel to the parent tsserver process.
Sources: src/typingsInstaller/nodeTypingsInstaller.ts84-187 src/typingsInstallerCore/typingsInstaller.ts79-105
NodeTypingsInstallerAdapter — tsserver BridgeNodeTypingsInstallerAdapter (src/tsserver/nodeServer.ts392-476) lives inside the tsserver process. It:
ts.server.TypingsInstallerAdaptercreateInstallerProcess() which forks typingsInstaller.js as a child process--globalTypingsCacheLocation, --logFile, --typingSafeListLocation, --typesMapLocation, --npmLocation, etc.installer.on("message", ...) to receive responses from the childDiagram: NodeTypingsInstallerAdapter Class Hierarchy
Sources: src/tsserver/nodeServer.ts392-476 src/typingsInstaller/nodeTypingsInstaller.ts84-100 src/typingsInstallerCore/typingsInstaller.ts116-143
The global cache stores installed @types packages across all projects so they don't need to be reinstalled per-project.
Default location by platform (determined by getGlobalTypingsCacheLocation() in src/tsserver/nodeServer.ts):
| Platform | Path |
|---|---|
| Windows | %LOCALAPPDATA%\Microsoft\TypeScript\ |
| macOS | ~/Library/Application Support/TypeScript/ |
| Linux | ~/.local/share/TypeScript/ (XDG-aware) |
The cache directory contains:
package.json — tracks installed devDependencies (@types/*)package-lock.json — lockfile used to detect out-of-date entriesnode_modules/@types/<pkg>/ — installed declaration filesnode_modules/types-registry/index.json — registry of all available @types packagesprocessCacheLocation() reads these files to pre-populate packageNameToTypingLocation, avoiding redundant installs.
Sources: src/tsserver/nodeServer.ts624-650 src/typingsInstallerCore/typingsInstaller.ts288-355
The types-registry npm package (node_modules/types-registry/index.json) is a JSON file with an entries field mapping package names to version maps:
{
"entries": {
"jquery": { "latest": "3.5.14", "ts4.0": "3.5.9", ... },
"node": { "latest": "20.11.5", ... },
...
}
}
isTypingUpToDate() (src/jsTyping/jsTyping.ts61-64) checks if a cached typing version is still current by comparing it against ts<major>.<minor> or "latest" in the registry. Outdated entries are queued for reinstallation.
Sources: src/typingsInstaller/nodeTypingsInstaller.ts51-77 src/jsTyping/jsTyping.ts54-64
TypeAcquisition ConfigurationThe TypeAcquisition interface (referenced throughout jsTyping) controls ATA behavior per-project:
| Field | Type | Effect |
|---|---|---|
enable | boolean | Enables or disables ATA entirely |
include | string[] | Packages to always acquire |
exclude | string[] | Packages to never acquire |
disableFilenameBasedTypeAcquisition | boolean | Skips SafeList filename matching |
For inferred and configured projects, typeAcquisition is sourced from tsconfig.json. For external projects (e.g., .csproj), it can be provided directly in the openExternalProject request.
Sources: src/jsTyping/jsTyping.ts116-165 src/testRunner/unittests/tsserver/typingsInstaller.ts162-188
ATA can be fully disabled by passing --disableAutomaticTypingAcquisition to tsserver. When this flag is present, NodeTypingsInstallerAdapter is not instantiated:
Sources: src/tsserver/nodeServer.ts492-494 src/tsserver/nodeServer.ts604
Diagram: Full ATA Lifecycle for a JS Project
Sources: src/typingsInstallerCore/typingsInstaller.ts195-237 src/typingsInstaller/nodeTypingsInstaller.ts138-166 src/tsserver/nodeServer.ts462-474
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.