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 |
Sources: src/typingsInstallerCore/typingsInstaller.ts116-400 src/typingsInstaller/nodeTypingsInstaller.ts84-187 src/tsserver/nodeServer.ts392-476 src/jsTyping/jsTyping.ts76-200
The two sides of ATA exchange typed messages over IPC. All message kinds are defined as string literal types.
Diagram: ATA Message Flow
Sources: src/typingsInstallerCore/typingsInstaller.ts145-169 src/typingsInstaller/nodeTypingsInstaller.ts138-155
| 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 |
Sources: src/typingsInstallerCore/typingsInstaller.ts161-169 src/typingsInstaller/nodeTypingsInstaller.ts128-133
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 src/typingsInstaller/nodeTypingsInstaller.ts90-99
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 |
Sources: src/typingsInstallerCore/typingsInstaller.ts116-143 src/typingsInstallerCore/typingsInstaller.ts363-365
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:
ensurePackageDirectoryExists(globalTypingsCacheLocation) to set up the cache directory src/typingsInstaller/nodeTypingsInstaller.ts112npm install --ignore-scripts types-registry@<latestDistTag> to get a fresh list of available @types packages src/typingsInstaller/nodeTypingsInstaller.ts118node_modules/types-registry/index.json via loadTypesRegistryFile() src/typingsInstaller/nodeTypingsInstaller.ts135process.on("message", ...) loop to handle incoming requests.installWorker() 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).
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.TypingsInstallerAdapter.createInstallerProcess() which forks typingsInstaller.js as a child process src/tsserver/nodeServer.ts413-441--globalTypingsCacheLocation, --logFile, --typingSafeListLocation, --typesMapLocation, --npmLocation, etc.installer.on("message", ...) to receive responses from the child src/tsserver/nodeServer.ts462-474Diagram: 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 entries.node_modules/@types/<pkg>/ — installed declaration files.node_modules/types-registry/index.json — registry of all available @types packages.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", ... },
...
}
}
Sources: src/typingsInstaller/nodeTypingsInstaller.ts51-77 src/jsTyping/jsTyping.ts54-64
TypeAcquisition ConfigurationThe TypeAcquisition interface 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.
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