Skip to content
ExponaBLOG
JAVASCRIPT & TYPESCRIPT · DAY 061 / 100

DefinitelyTyped: a practical JavaScript & TypeScript guide

Community types for the JavaScript ecosystem.

Expona Admin7 min read

DefinitelyTyped: Community Types for the JavaScript Ecosystem

After 60 days of building your TypeScript muscle, you've likely hit a wall: you're using a popular JavaScript library that has zero type definitions. Welcome to DefinitelyTyped, the community-driven repository that provides TypeScript type definitions for thousands of untyped or poorly typed npm packages. If you're serious about shipping type-safe code in production, understanding how to use, maintain, and contribute to DefinitelyTyped is essential.

What is DefinitelyTyped and Why It Matters

DefinitelyTyped is a centralized repository on GitHub containing TypeScript declaration files for libraries that either predate TypeScript or don't maintain their own types. When a library doesn't ship index.d.ts files, the community steps in. These type definitions live under the @types scope on npm, letting you add types to any legacy or third-party library you depend on.

I've encountered this countless times in production systems. A team wants to use a solid, battle-tested library for, say, image manipulation or PDF generation, but it was written in plain JavaScript five years ago. Without DefinitelyTyped, you'd either:

  • Disable TypeScript checks with @ts-ignore (terrible for maintainability)
  • Write your own type definitions from scratch (time-consuming and often incomplete)
  • Avoid the library entirely (limiting your options)

DefinitelyTyped eliminates that friction. It's a safety net that bridges the gap between the evolving TypeScript ecosystem and decades of valuable JavaScript libraries.

Installing @types/package: The Basics

Installing types from DefinitelyTyped is straightforward. If you need types for a package called lodash, you install the scoped package @types/lodash.

typescript
npm install --save-dev @types/lodash

After installation, TypeScript automatically picks up the types. No configuration needed. Here's a practical example:

typescript
import _ from 'lodash';

// Without @types/lodash, this would be:
// const isEqual: any
// With @types/lodash, TypeScript knows the signature:
const isEqual = _.isEqual([1, 2, 3], [1, 2, 3]);
// TypeScript infers: boolean

// You get full autocomplete and error checking
const result = _.map([1, 2, 3], (n: number) => n * 2);
console.log(result); // number[]

In a real e-commerce platform I built, we used lodash extensively for data transformation. Before adding @types/lodash, we were constantly second-guessing what functions returned. After installing it, our team caught type mismatches immediately, preventing subtle bugs in production.

Pro tip: If a package has a slash in its name (like @babel/core), the types follow the same pattern: @types/babel__core. The slash becomes double underscores.

Versions Follow the Library

This is critical and often misunderstood. The version number of @types/package should match the major version of the library you're using. If you're on lodash 4.x, install @types/lodash@4. If you upgrade to a hypothetical lodash 5, you'd upgrade types to @types/lodash@5.

Here's why this matters. Type definitions encode the API surface of a library. If a function signature changed between versions, the types need to reflect that. Installing mismatched versions leads to confusion and false negatives.

typescript
// Scenario: You're on React 17, but accidentally installed @types/react@18
import React from 'react';

// In React 17, children is a direct prop
interface Props {
  children: React.ReactNode;
}

// In React 18, the API changed. Your types claim the new interface,
// but your runtime is the old one. This mismatch causes bugs.
const MyComponent: React.FC = ({ children }) => {
  return <div>{children}</div>;
};

Always check the main package's version and align your @types accordingly. Most modern npm clients (npm 8+, pnpm) can help you audit this:

typescript
npm list @types/lodash
// Shows which version you have installed

In a CRM system I maintained, a junior dev upgraded React but forgot to upgrade the types. Deployment went smooth, but we had type errors locally that didn't match the runtime behavior. It took hours to debug. Keep versions in sync.

Prefer Libraries with Built-in Types

While DefinitelyTyped is invaluable, the best types are those maintained by the library author. Built-in types mean:

  • Types are updated alongside code changes
  • No version mismatch risk
  • Authors have full context of API design decisions
  • Faster feedback loop for type improvements

Modern libraries increasingly include types out of the box. Express now ships with types. Axios includes them. Redux Toolkit has excellent type support. When evaluating a library, check if it has a types field in package.json:

typescript
// package.json of a well-typed library
{
  "name": "my-library",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",  // <-- Points to declaration files
  "files": ["dist", "package.json"]
}

I've standardized this across all new projects I start. When choosing dependencies, "has built-in types" is now a checkbox in my evaluation criteria, equal to "active maintenance" and "good test coverage."

That said, don't avoid a genuinely good library just because it lacks types. Sometimes the DefinitelyTyped types are mature and well-maintained. But if you're building greenfield, prioritize libraries with native TypeScript support.

Report or Fix Incorrect Types

Here's the thing about community-driven type definitions: they're only as good as the community maintains them. You'll eventually find a type that's wrong, incomplete, or outdated. When you do, you have two paths: report it or fix it.

Reporting an Issue

If you spot incorrect types, open an issue on the DefinitelyTyped GitHub repository. Be specific:

  • Which package and which version
  • What the types claim vs. what the runtime does
  • Minimal reproducible example
typescript
// Example: @types/lodash claims map returns T[], but actually returns Array
import _ from 'lodash';

const data = { a: 1, b: 2, c: 3 };
const mapped = _.map(data, (value, key) => `${key}: ${value}`);

// Types say: string[]
// Runtime says: string[] (in this case, correct)
// But for objects, it should be: string[]
// Issue: lodash.map has inconsistent typing for objects vs arrays

Contributing a Fix

If you're comfortable, submit a pull request to DefinitelyTyped. The process is straightforward but has strict guidelines. I've submitted a few fixes myself, and the maintainers are thorough but fair.

Here's a minimal example of a type definition you might fix:

typescript
// Before (incorrect)
declare function processData(data: any): any;

// After (correct)
declare function processData(data: Record): {
  success: boolean;
  result: number[];
  error?: string;
};

Steps to contribute:

  1. Fork the DefinitelyTyped repo
  2. Navigate to types/package-name
  3. Edit the index.d.ts file
  4. Run tests: npm test
  5. Submit PR with clear description of what was fixed

The maintainers require your types to pass automated tests and match the library's actual behavior. It's rigorous, but that's why DefinitelyTyped types are trusted across millions of projects.

Common Mistakes

Mistake 1: Installing types as a production dependency. Types are development-only. Always use --save-dev. They're not needed at runtime and bloat your bundle.

typescript
// Wrong
npm install @types/lodash

// Right
npm install --save-dev @types/lodash

Mistake 2: Ignoring version mismatches. If your library updates to v5 and you forget to update @types/library, you'll have silent type errors. Set up npm audit or use a tool like Renovate to catch these automatically.

Mistake 3: Using @ts-ignore as a band-aid. If a type is wrong, fix it or report it. @ts-ignore should be rare and always accompanied by a comment explaining why. It's not a substitute for proper types.

typescript
// Bad
// @ts-ignore
const result = someUntypedFunction();

// Good (when absolutely necessary)
// @ts-ignore - types are incorrect for this overload, reported in #12345
const result = someUntypedFunction();

Mistake 4: Assuming DefinitelyTyped types are always correct. They're community-maintained. Review types when they seem suspicious, especially in critical paths. Trust, but verify.

Key Takeaways

  • DefinitelyTyped fills the gap between TypeScript and untyped JavaScript libraries via the @types npm scope.
  • Install types as dev dependencies: npm install --save-dev @types/package. TypeScript picks them up automatically.
  • Keep versions aligned: @types/package version should match your library's major version to avoid API mismatches.
  • Prefer built-in types: When choosing libraries, favor those with native TypeScript support. They're better maintained and less fragile.
  • Contribute back: When you find incorrect or missing types, report issues or submit PRs. DefinitelyTyped improves because people like you care about type quality.
  • Audit regularly: Use npm list @types/* and npm audit to catch version mismatches and outdated type packages before they cause production issues.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles