Skip to main content

Packages That Ship TypeScript Types vs DefinitelyTyped

·PkgPulse Team

TL;DR

In 2026, 78% of the top 1000 npm packages ship their own TypeScript types, up from 45% in 2020. Bundled types are always better: they're versioned with the package, maintained by the same team, and never lag behind breaking changes. DefinitelyTyped (@types/) still has ~10,000 packages but should be considered a legacy fallback — for new projects, prioritize packages with built-in types.

Key Takeaways

  • 78% of top 1000 packages now ship built-in TypeScript types (2026)
  • @types/ lag problem: DefinitelyTyped types can be months behind the actual package
  • Version mismatch pain: package@2.0 with @types/package@1.9 → silent errors
  • "types" field in package.json — how to check for built-in types
  • TypeScript-first packages tend to have better documentation and fewer runtime surprises

Built-In Types vs DefinitelyTyped

// Built-in types (best): types are IN the package
// package.json:
{
  "name": "fastify",
  "version": "4.24.0",
  "types": "fastify.d.ts"     // ← types ship with package
  // OR:
  "exports": {
    ".": {
      "types": "./index.d.ts"
    }
  }
}

// DefinitelyTyped (@types/): types are a SEPARATE package
// npm install express
// npm install -D @types/express  ← separate install, separate version

// The problem: express@4.18.2 + @types/express@4.17.21
// Package: 4.18.2 | Types: 4.17.21 → 1 minor version behind
// Can cause: missing types for new methods, wrong signatures

How to Check Which Type System a Package Uses

# Method 1: npm page
# npmjs.com/package/fastify — will show TypeScript badge if types bundled

# Method 2: Check package.json
npm view fastify --json | jq '.types, .typings, .exports'
# If any of these return a .d.ts path: built-in types ✅
# If all null: needs @types/ or has no types

# Method 3: Check package contents
npm pack fastify --dry-run | grep .d.ts
# Shows .d.ts files in the package

# Method 4: PkgPulse
# Health score includes TypeScript support indicator
# pkgpulse.com/compare/fastify-vs-express

# Quick check via TypeScript:
import fastify from 'fastify';
// If TypeScript finds types without @types/: built-in ✅
// If TypeScript errors: needs @types/ or no types available

Major Packages: Built-In Types ✅

// These packages ship their own types — no @types/ needed:

// Web frameworks:
import Fastify from 'fastify';        // fastify ✅
import { Hono } from 'hono';          // hono ✅
// import Koa from 'koa';             // ❌ needs @types/koa

// State management:
import { create } from 'zustand';     // zustand ✅
import { atom } from 'jotai';        // jotai ✅
import { proxy } from 'valtio';      // valtio ✅

// Data fetching:
import { useQuery } from '@tanstack/react-query';  // ✅
import { ofetch } from 'ofetch';     // ofetch ✅

// Validation:
import { z } from 'zod';             // zod ✅
import * as v from 'valibot';        // valibot ✅

// ORM:
import { drizzle } from 'drizzle-orm';  // drizzle-orm ✅
import { PrismaClient } from '@prisma/client';  // prisma (generated) ✅

// Build tools (cli only, but types for config):
// vite.config.ts: built-in types for defineConfig ✅

// Test runners:
import { describe, it, expect } from 'vitest';  // vitest ✅
// Jest: needs @types/jest ❌ (or jest/globals if configured)

// Logging:
import pino from 'pino';             // pino ✅

// Date:
import dayjs from 'dayjs';          // dayjs ✅
import { format } from 'date-fns';  // date-fns ✅

Packages That Still Need @types/

// DefinitelyTyped still needed for:

// Old guard (pre-TypeScript era):
npm install -D @types/express   // express (old but stable)
npm install -D @types/node      // Node.js built-ins (runtime types)
npm install -D @types/react     // react (types are separate by design)
npm install -D @types/react-dom

// express: has been promised built-in types since v5, not yet shipped
// react: intentional separation from @types/react, maintained by community

// Testing:
npm install -D @types/jest      // jest (if not using jest/globals)
npm install -D @types/mocha     // mocha

// Utility libraries:
npm install -D @types/lodash    // lodash
npm install -D @types/uuid      // uuid (v9+ has built-in types actually)

// Note: @types/node is special — it's always needed for Node.js APIs
// even if you're using packages with built-in types

The Version Mismatch Problem

// Real example: express breaking types between versions
// package.json:
{
  "dependencies": {
    "express": "^4.18.0"   // Installed: 4.18.2
  },
  "devDependencies": {
    "@types/express": "^4.17.0"  // Installed: 4.17.21
  }
}

// Problem: express added new methods/changed signatures in 4.18
// @types/express@4.17.21 doesn't know about them
// TypeScript says: no error ✅
// Runtime: behavior differs from types ❌

// This happened with:
// - Node.js fetch types vs @types/node
// - react-router-dom between major versions
// - Several AWS SDK types

// Solution: lock @types/ versions tightly
// "@types/express": "4.17.21"  ← exact, not ^
// Or better: pick packages with built-in types

TypeScript Adoption in npm: The Data

TypeScript type support across npm packages (2026):

Top 100 packages:    95% have types (bundled or @types/)
Top 1,000 packages:  89% have types
Top 10,000 packages: 78% have types
All packages:        ~40% have types (long tail is JS-only)

Of packages WITH types:
- Bundled types: 78%  (up from 45% in 2020)
- Only @types/: 22%  (declining as packages migrate)

Why bundled types are growing:
1. TypeScript itself grew: ~68% of JS devs use TS (State of JS 2025)
2. Package authors feel pressure to support TypeScript properly
3. npm shows TS badge prominently → drives competitive behavior
4. tRPC/Zod pattern: end-to-end types REQUIRE bundled types to work

How to Check Type Quality (Not Just Presence)

// Having types isn't enough — type QUALITY matters

// Red flags in @types/ packages:
// ❌ Everything typed as `any`
declare function doThing(options: any): any;

// ❌ Missing generics
declare function useQuery(key: string, fn: Function): any;
// Should be:
declare function useQuery<T>(key: string, fn: () => Promise<T>): { data: T | undefined };

// ❌ Types in wrong export location (export default vs export =)
// Causes: "Module has no exported member" errors

// ✅ Good type quality signals:
// - Generics used throughout
// - Return types inferred from input types
// - Utility types used correctly (Partial, Required, Pick, Record)
// - TypeScript strict mode compatibility
// - Types tested in the package's own test suite (dts-jest or tsd)

tsconfig Best Practices with @types/

// tsconfig.json
{
  "compilerOptions": {
    // Only include @types/ packages you explicitly need
    // Without this, TypeScript includes ALL installed @types/ automatically
    "types": ["node", "jest"],

    // Or: don't specify "types" and let TypeScript auto-discover
    // Better for most projects

    // Check type version compatibility:
    "skipLibCheck": true,  // Skip type checking of declaration files
    // Use this if you hit type conflicts between @types/ packages
    // Not ideal but sometimes necessary with complex dep trees

    // Better alternative:
    "skipLibCheck": false,  // Keep it on, fix the root cause
  }
}

Migrating Off DefinitelyTyped

# Check if a package now ships its own types (many did since 2022):

# uuid migrated in v9:
# Before: npm install uuid @types/uuid
# After (uuid v9+): npm install uuid  ← no @types/ needed
npm view uuid --json | jq '.types'
# Returns: "dist/cjs/index.d.ts" ✅

# If a package you use added built-in types:
npm uninstall @types/package-name
npm install package-name@latest
# TypeScript should pick up the bundled types automatically

The Future: TypeScript-Native Packages

// Trend: packages written in TypeScript from day 1
// No .js + .d.ts dance — TypeScript source → distribution

// Tools that compile packages:
// tsup: builds both CJS and ESM with types from a single TypeScript source
// unbuild: used by Nuxt ecosystem packages
// pkgroll: Rollup-based, type-aware

// package.json pattern for TypeScript-native packages:
{
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "require": "./dist/index.cjs",
      "import": "./dist/index.mjs",
      "types": "./dist/index.d.ts"
    }
  }
}
// This is the modern standard — CJS + ESM + types, single package

Compare TypeScript support and package health on PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.