DefinitelyTyped (@types)
Thousands of JavaScript packages were written before TypeScript existed and ship no type information of their own. DefinitelyTyped is the community-maintained repository that fills this gap — a massive collection of type declaration packages published under the @types npm scope.
Understanding how @types packages work, when to use them, and how they interact with your tsconfig.json is essential knowledge for every TypeScript developer.
The Problem @types Solves
When you import a plain JavaScript package like lodash, TypeScript cannot infer its API. Without type information, every usage is typed as any, defeating the purpose of using TypeScript.
There are three ways a package can ship types:
- Bundled types — the package ships its own
.d.tsfiles (modern packages do this) @types/*package — the community maintains declarations in DefinitelyTyped- No types — you write your own declarations (covered in the next section)
Package type | Example | What to do |
|---|---|---|
Bundled types | axios, zod, prisma | Nothing — types come with the install |
@types package available | lodash, express, node | npm install --save-dev @types/package-name |
No types anywhere | some legacy lib | Write your own .d.ts file |
Installing @types Packages
@types packages are always devDependencies — they only exist at build time, never at runtime.
# Install the types for Node.js built-ins npm install --save-dev @types/node # Install types for Express npm install express npm install --save-dev @types/express # Install types for lodash npm install lodash npm install --save-dev @types/lodash # Install types for Jest npm install --save-dev jest @types/jest
@types packages from your node_modules/@types folder — you do not need to reference them explicitly in most cases.How TypeScript Resolves @types
By default, TypeScript includes all @types packages found in node_modules/@types throughout your entire directory hierarchy. This means @types/node installed in a parent node_modules folder is picked up automatically.
You can control this behaviour with two tsconfig.json options:
// tsconfig.json
{
"compilerOptions": {
// Only include these specific @types packages globally
"types": ["node", "jest"],
// Search for @types in these directories instead of node_modules
"typeRoots": ["./node_modules/@types", "./src/types"]
}
}types array, TypeScript will ONLY auto-include the packages you list. All others must be explicitly referenced with a triple-slash directive or an import. Omit types entirely to keep the default behavior of including everything.The types vs typeRoots Options
Option | What it does | When to use |
|---|---|---|
types | Whitelist of @types packages to auto-include globally | Limit which globals bleed into your code |
typeRoots | Directories to search for @types folders | Add a local types folder alongside node_modules/@types |
(neither set) | Include ALL @types packages found in node_modules | Default — correct for most projects |
Checking if a Package Has @types
The fastest way to check is to visit the TypeSearch tool at typesearch.net or simply check npm.
If a package ships its own types, its package.json will have a "types" or "typings" field:
# Check if axios bundles its own types
node -e "const p = require('axios/package.json'); console.log(p.types || p.typings)"
# Output: index.d.ts
# Check if lodash bundles types (it doesn't — use @types/lodash)
node -e "const p = require('lodash/package.json'); console.log(p.types)"
# Output: undefined# You can also just try to install and see what the compiler says: npm install lodash # In your editor: import _ from 'lodash'; # TypeScript error: Could not find a declaration file for module 'lodash'. # Try: npm i --save-dev @types/lodash
What's Inside an @types Package
An @types package is simply a folder containing .d.ts declaration files. Let's look at the structure of @types/node to understand the pattern:
node_modules/@types/node/ index.d.ts ← main entry (re-exports all modules) fs.d.ts ← types for the 'fs' module path.d.ts ← types for the 'path' module http.d.ts ← types for the 'http' module events.d.ts ← types for the 'events' module package.json ← points to index.d.ts ...
// When you write this in your code:
import { readFileSync } from 'fs';
import { join } from 'path';
// TypeScript resolves:
// node_modules/@types/node/fs.d.ts → readFileSync type
// node_modules/@types/node/path.d.ts → join type
const content = readFileSync(join(__dirname, 'config.json'), 'utf-8');
// ^? string (typed correctly thanks to @types/node)Version Alignment
@types package versions follow the version of the library they describe. The major and minor version of an @types package should match the major and minor version of the package it types.
# If you have express@4.18.x, install the 4.x types: npm install --save-dev @types/express@^4 # If you have express@5.x, install the 5.x types: npm install --save-dev @types/express@^5
// Good version alignment in package.json
{
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/lodash": "^4.14.202",
"@types/node": "^20.0.0"
}
}npx npm-check-updates periodically to keep both your packages and their @types counterparts in sync.Triple-Slash References
Sometimes you need to explicitly pull in a type package that isn't auto-included. Triple-slash directives are single-line comments at the top of a file that instruct the compiler to include additional files.
/// <reference types="node" />
/// <reference types="jest" />
// Now __dirname and describe() are available in this file
// even if they aren't globally included by tsconfig.json
describe('file utilities', () => {
it('resolves paths', () => {
const p = require('path').join(__dirname, 'fixtures');
expect(p).toContain('fixtures');
});
});.d.ts files and library code. In regular application code, simply configure tsconfig.json and let automatic resolution handle it.When @types Conflicts With Bundled Types
Occasionally a package ships its own types but a stale @types package is also installed, causing duplicate or conflicting declarations. The fix is to remove the redundant @types package.
# axios bundles its own types since v1.0 # If you also have @types/axios installed, remove it: npm uninstall @types/axios
// Check which types file TypeScript is actually using: // Hover over the import in your editor, or: import axios from 'axios'; // ^? — hover shows the resolved type file path // Or check with tsc directly: // npx tsc --traceResolution 2>&1 | grep axios
Patching @types With Your Own Declarations
When an @types package is missing a property or has an incorrect type, you can patch it using module augmentation instead of waiting for a pull request to be merged.
// src/types/lodash.d.ts
// Imagine @types/lodash is missing a function we need to type
import 'lodash';
declare module 'lodash' {
interface LoDashStatic {
// Add the missing method signature
sumBy<T>(collection: T[], iteratee: (item: T) => number): number;
}
}
// Now TypeScript accepts this without errors:
import _ from 'lodash';
const total = _.sumBy(orders, (o) => o.price);The DefinitelyTyped Repository
The DefinitelyTyped repository lives at github.com/DefinitelyTyped/DefinitelyTyped. It is one of the largest open-source repositories on GitHub with over 8,000 type packages.
Contributing Types
If you need to add or fix types for a package, the contribution process is:
Fork the DefinitelyTyped repository on GitHub.
Find or create the folder: types/package-name/index.d.ts
Write your type declarations following the DefinitelyTyped conventions.
Add tests in types/package-name/package-name-tests.ts
Run the local test suite: cd types/package-name && npx dtslint .
Open a pull request — the DT bot will automatically review and publish.
types/
lodash/
index.d.ts ← the declarations
lodash-tests.ts ← usage tests (must compile without errors)
tsconfig.json ← tsconfig for running the tests
package.json ← metadata (owners, dependencies)Practical Example: Typing an Express App
Here's a complete setup for a typed Express application, showing all the pieces working together.
npm install express npm install --save-dev typescript @types/node @types/express ts-node
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node"
},
"include": ["src/**/*"]
}// src/app.ts
import express, { Request, Response, NextFunction } from 'express';
// All types come from @types/express
const app = express();
app.use(express.json());
// Route handler — req and res are fully typed
app.get('/users/:id', (req: Request, res: Response) => {
const { id } = req.params; // string
const { format } = req.query; // string | ParsedQs | string[] | ParsedQs[]
res.json({ id, format });
});
// Error handler — four-parameter signature required by Express
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
res.status(500).json({ error: err.message });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});@types/express installed, you get complete IntelliSense for the entire Express API — request params, query strings, response methods, middleware signatures, and more.Summary
DefinitelyTyped is a community repository of type declarations for JavaScript packages that ship no types.
@types packages are always devDependencies — they're consumed at compile time only.
TypeScript auto-includes all @types packages in node_modules/@types by default.
Use the tsconfig "types" array to whitelist which @types are globally available.
Keep @types versions aligned with the major.minor version of the package they type.
Use module augmentation to patch incorrect or incomplete @types declarations.
Triple-slash directives explicitly include a types package in a single file.
When a package starts bundling its own types, remove the corresponding @types package to avoid conflicts.
Understanding skipLibCheck
One tsconfig flag frequently seen alongside @types usage is skipLibCheck: true. It tells TypeScript to skip type-checking inside .d.ts files — including those in node_modules/@types.
// tsconfig.json
{
"compilerOptions": {
"skipLibCheck": true // skip type-checking all .d.ts files
}
}When to use skipLibCheck
Use it when:
- Different
@typespackages declare conflicting global types (common with@types/nodeand browser globals) - A transitive dependency ships broken
.d.tsfiles you cannot fix - Build speed matters and you trust your dependencies
Do not rely on it to hide bugs in your own declaration files — those should be fixed properly.
A more surgical alternative is skipDefaultLibCheck: true, which only skips TypeScript's built-in lib files, not third-party .d.ts files.
// Common conflict example: @types/node vs browser globals
// @types/node declares 'global' as a namespace
// Browser code also uses 'global' patterns
// If you hit duplicate identifier errors from @types packages:
// Option 1 — skipLibCheck: true (broad)
// Option 2 — use the 'types' array to be selective:
// { "types": ["node"] } // only include @types/node, exclude conflicting packagesChecking Type Coverage
The type-coverage tool measures what percentage of your codebase has explicit types vs implicit any. Use it to track progress when migrating a JavaScript codebase.
# Install type-coverage npm install --save-dev type-coverage # Run — reports percentage of typed nodes npx type-coverage # Coverage: 95.23% (12034/12638) # Show all any-typed locations npx type-coverage --detail # Fail CI if coverage drops below a threshold npx type-coverage --atLeast 95
type-coverage check to your CI pipeline. As you install @types packages and write declarations, coverage should trend upward toward 100%.Summary
DefinitelyTyped is a community repository of type declarations for JavaScript packages that ship no types.
@types packages are always devDependencies — they're consumed at compile time only.
TypeScript auto-includes all @types packages in node_modules/@types by default.
Use the tsconfig "types" array to whitelist which @types are globally available.
Keep @types versions aligned with the major.minor version of the package they type.
Use module augmentation to patch incorrect or incomplete @types declarations.
Triple-slash directives explicitly include a types package in a single file.
When a package starts bundling its own types, remove the corresponding @types package to avoid conflicts.
skipLibCheck: true skips type-checking inside .d.ts files — useful when packages conflict.
Track type coverage with the type-coverage tool to measure migration progress.