-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
161: Publishing Type Definitions with a Package
I've seen this happen more times than I can count: a developer spends weeks crafting a beautiful, type-safe library in TypeScript, publishes it to npm, and then gets a flurry of GitHub issues saying, "Hey, I'm getting any for everything!" They're confused because their source code is perfectly typed. They assume that because the package was written in TypeScript, the types are magically bundled in.
The Myth: TypeScript source files provide types to the consumer
Here is the reality: npm packages are generally consumed as JavaScript. When you run npm install, the consumer isn't typically compiling your TypeScript source on their end; they are importing the compiled .js files from your dist or lib folder. If you only publish your compiled JS, the type information is stripped away during the build process. Even if you include your .ts files in the package, most build tools and IDEs won't look at them for type definitions because they're looking for specifically formatted declaration files.
Let's look at a real example. Imagine we're building a small utility called tx-validator to handle payment transactions:
// src/index.ts
export interface Transaction {
id: string;
amount: number;
currency: 'USD' | 'EUR' | 'GBP';
}
export function validateTransaction(tx: Transaction): boolean {
return tx.amount > 0 && tx.id.length > 5;
}
If you just compile this to JS and publish it, the user sees validateTransaction(tx: any): any. The "source of truth" is gone.
The Fix: Generating Declarations and Mapping the Entry Point
To fix this, you need to ship Declaration Files (.d.ts). These are essentially "header files" for TypeScript; they contain only the type signatures without the actual logic. This keeps your package lean while still giving the consumer full autocomplete and type checking.
First, you have to tell the compiler to actually generate these files. In your tsconfig.json, you need to enable the declaration flag:
{ "compilerOptions": { "target": "ES6", "module": "CommonJS", "declaration": true, // This is the magic switch "outDir": "./dist", "rootDir": "./src" } }When you run
tscnow, you'll notice that for every.jsfile in yourdistfolder, there is a corresponding.d.tsfile. But we aren't done. TypeScript doesn't just "guess" where these types are; you have to explicitly point the consumer to them in yourpackage.json.I usually see people forget the
typesfield. Here is how yourpackage.jsonshould look:{ "name": "@my-org/tx-validator", "version": "1.0.0", "main": "dist/index.js", "types": "dist/index.d.ts", // This tells TS where the definitions live "files": [ "dist" ] }By adding that
typesfield, you're telling the TypeScript compiler: "When someone imports from this package, look at this specific file to figure out what the shapes of the objects are."One quick pro-tip: if your package is purely TypeScript and you're using a bundler like Rollup or esbuild, you might need a plugin (like
rollup-plugin-dts) to "roll up" all your declaration files into one singleindex.d.ts. It's much cleaner for the consumer than having a mirrored folder structure of a hundred tiny.d.tsfiles.
📋 Practical Task
Packaging the 'GeoCoordinate' Utility with Types
You are tasked with preparing a small utility library called geo-utils for publication. The library provides a type for coordinates and a function to calculate the distance between two points. Currently, the project is set up to compile JS, but it's missing the type definitions for the end-user.
Your Goal: Configure the project so that when it is published, consumers will have full type support for the Coordinate interface and the getDistance function.
Files provided:
src/index.ts: Contains theCoordinateinterface andgetDistancefunction.tsconfig.json: Currently has"declaration": false.package.json: Missing thetypesfield.
Requirements:
- Modify
tsconfig.jsonto ensure declaration files are emitted during compilation. - Update
package.jsonto map the type definitions to the resulting file in thedistfolder (assuming the output isdist/index.d.ts). - Verify that the
filesarray inpackage.jsonincludes thedistdirectory so the types are actually uploaded to npm.
There are no comments for now.