TypeScript
Completed
-
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
52: Publishing a Typed npm Package
A few years ago, a colleague of mine named Sarah spent an entire weekend building a sleek utility for handling complex API pagination. She was thrilled with the type safety she'd baked into it, and she pushed it to npm with a sense of pride. Ten minutes later, a senior dev from another team Slacked her: "Cool library, Sarah, but why do I have to use // @ts-ignore on every single function call?" Sarah was confused—the code was written in TypeScript! The problem was that while the source was typed, she hadn't provided the definitions. To the rest of the world, her package looked like plain, untyped JavaScript.
This is a classic mistake. When you publish a package, you aren't just sharing your code; you're sharing a contract. If you want your users to get that sweet autocomplete and compile-time validation you enjoyed while writing the library, you have to ship the type definitions alongside the compiled JavaScript. You can't just publish your .ts files because npm users (and Node.js) can't execute those directly.
Generating the Declaration Files
To fix the problem Sarah had, we need TypeScript to generate .d.ts files. These are "declaration" files—they contain only the type information, stripped of the actual logic. They act as a map that tells the consumer's editor exactly what types are being passed in and out of your functions.
Let's say we're building a small utility called date-range-helper. Your tsconfig.json needs two critical settings to make this work. First, declaration: true tells the compiler to output those .d.ts files. Second, you need an outDir (like dist or lib) so your compiled JS and your type definitions aren't cluttering up your src folder.
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"declaration": true,
"outDir": "./dist",
"strict": true
},
"include": ["src"]
}
When you run tsc, TypeScript will now mirror your source structure inside the dist folder. For every index.ts, you'll get an index.js (the logic) and an index.d.ts (the types). If you don't do this, your users are essentially flying blind.
Mapping the Package Entry Points
Once the files exist in your dist folder, you have to tell npm how to find them. A package.json file is more than just a list of dependencies; it's the directory for your package. Most developers are familiar with the main field, which points to the JavaScript entry point, but for a typed package, the types (or typings) field is just as important.
If you leave the types field out, TypeScript will try to guess where the definitions are by looking for a .d.ts file with the same name as your main file. That usually works, but being explicit prevents weird bugs in different IDEs. Here is how your package.json should look for our date-range-helper:
{
"name": "@your-username/date-range-helper",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "tsc"
}
}
I added a files array there for a reason. By default, npm publishes everything in your folder. You don't want to ship your tsconfig.json, your tests, or your raw src files to the user. By specifying "dist", you ensure the package is lean and contains only what's necessary for the code to run and the types to be validated. I've found that keeping your published package small not only looks professional but also speeds up npm install times for everyone else.
📋 Practical Task
Build and Package the "string-case-converter" Utility
Your goal is to set up a project structure for a library called string-case-converter that allows users to convert strings to kebab-case or snake_case. You aren't actually publishing to the npm registry, but you must configure the project so that it is "publish-ready."
Requirements:
- Create a
src/index.tsfile with a functionconvertCase(str: string, mode: 'kebab' | 'snake'): string. - Configure
tsconfig.jsonto enable declaration file generation and output all compiled files to adistfolder. - Configure
package.jsonwith the correctmainandtypesfields pointing to the compiled files in thedistfolder. - Add a
filesarray topackage.jsonto ensure only thedistdirectory is included in the final bundle. - Run the build command and verify that both
index.jsandindex.d.tsexist in thedistfolder.
There are no comments for now.