three-versions-types
Understand the Three Versions Involved in Type Declarations
Overview
When working with TypeScript types, three versions must align: the version of the package you're using, the version of its type declarations (@types), and the version of TypeScript itself. Misalignment between these versions can cause confusing type errors even when the code works at runtime.
Understanding these three versions helps diagnose and prevent type compatibility issues.
The Three Versions
- Package version - The runtime library (e.g., lodash@4.17.21)
- @types version - Type declarations (e.g., @types/lodash@4.14.191)
- TypeScript version - Your TypeScript compiler (e.g., typescript@5.2.2)
When to Use This Skill
- Publishing type declarations
- Debugging version conflicts
- Working with @types packages
- Managing library dependencies
- Type errors that don't match runtime behavior
The Iron Rule
Keep package, @types, and TypeScript versions compatible. Update them together to avoid mysterious type errors.
Common Version Issues
// Package updated but @types not updated
import { newFeature } from 'library'; // Runtime works
// Error: Module 'library' has no exported member 'newFeature'
// TypeScript too old for new type features
// Error: Type instantiation is excessively deep
// (Newer @types use features old TS doesn't support)
// @types too new for package version
// Types reference features not in actual package
Best Practices
// package.json
{
"dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/lodash": "^4.14.191",
"typescript": "^5.2.2"
}
}
Checking Versions
# Check all three versions
npm ls lodash @types/lodash typescript
# Check for outdated packages
npm outdated
# Update together
npm update lodash @types/lodash typescript
Reference
- Effective TypeScript, 2nd Edition by Dan Vanderkam
- Item 66: Understand the Three Versions Involved in Type Declarations
More from marius-townhouse/effective-typescript-skills
module-by-module-migration
Use when migrating large codebases. Use when converting JavaScript to TypeScript. Use when managing dependencies. Use when planning migration order. Use when teams are adopting TypeScript.
11precise-string-types
Use when working with string-typed properties. Use when string values have a limited set of options. Use when keyof could provide better type safety.
10branded-types
Use when primitive types need semantic distinction. Use when string or number types have different meanings. Use when you need nominal typing.
10callback-this-type
Use when callbacks use this. Use when API provides this context. Use when typing event handlers. Use when library sets this in callbacks. Use when documenting callback context.
10structural-typing
Use when surprised by TypeScript accepting unexpected values. Use when designing function parameters. Use when testing with mock objects.
10iterate-objects-safely
Use when iterating over object keys and values. Use when for...in loops produce type errors. Use when Object.entries returns any types. Use when dealing with prototype pollution concerns. Use when considering Map vs object.
10