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
49: Typing Third-Party JavaScript Libraries
I see this happen all the time with developers transitioning to TypeScript: you find a perfect, lightweight JavaScript library that does exactly what you need, you npm install it, and then you're greeted by a sea of red squiggly lines. The immediate reaction is usually, "Great, I have to spend the next three hours writing a full type definition file for this library just to use one function."
The "I have to write everything from scratch" trap
The misconception is that if a library is written in plain JavaScript, you are solely responsible for defining its entire API surface in TypeScript. You might think that the lack of built-in types means the library is "incompatible" with your project, leading you to either abandon the library or—more commonly—cast everything to any and effectively turn off TypeScript for that entire module.
Let's look at a real example. Say you want to use canvas-confetti to celebrate a user completing a form. You install it and try this:
import confetti from 'canvas-confetti';
confetti({
particleCount: 100,
spread: 70,
});
TypeScript will likely scream at you: "Could not find a declaration file for module 'canvas-confetti'." If you believe the misconception, you'd start writing a .d.ts file from scratch. But in the modern ecosystem, that's almost never the first step.
Leveraging the community with DefinitelyTyped
Most of the time, someone else has already done the hard work. There is a massive community effort called DefinitelyTyped, which hosts type definitions for nearly every popular JS library. These are distributed via the @types scope on npm.
Instead of writing types, you just run:
npm install --save-dev @types/canvas-confetti
Once that's installed, the red lines vanish. TypeScript magically finds the types in node_modules/@types and maps them to the JS library. I always check for an @types package before I even think about writing a single line of custom type code. It's the "low hanging fruit" of TypeScript development.
When the community fails you: Custom Declaration Files
Now, what happens when you're using a niche library—maybe something internal to your company or a tiny project from a developer who didn't provide types? You can't install an @types package if it doesn't exist. This is where you actually have to step in, but here's the secret: you don't have to type the whole library.
You can create a "declaration file" (a .d.ts file) in your project to tell TypeScript what the library looks like. I usually create a folder called @types in my root directory and add a file named after the library.
If we had a fake library called super-calculator that only had one function we cared about, your super-calculator.d.ts would look like this:
declare module 'super-calculator' {
export function add(a: number, b: number): number;
export function multiply(a: number, b: number): number;
}
By doing this, you've told TypeScript: "Trust me, when I import from 'super-calculator', these functions exist and they take these types." You don't need to implement the logic; you're just describing the shape. If there are 50 other functions in that library you don't use, just leave them out. TypeScript is happy as long as the parts you are using are described.
One last tip: if you are in a massive rush and just need the code to compile, you can use declare module 'library-name'; without any body. This tells TypeScript the module exists, but everything inside it is any. It's a dangerous habit, but it's better than fighting the compiler for an hour when you're on a deadline. Just remember to come back and actually type it later.
📋 Practical Task
Defining Types for the "Easy-Chart" JS Library
You are integrating a small, legacy JavaScript library called easy-chart into your project. The library is not on DefinitelyTyped, and your team doesn't have time to type the whole thing. However, you need type safety for the two main functions you're using.
The Library API:
initChart(elementId: string, options: object): Initializes a chart. Returns aChartInstanceobject.updateData(instance: ChartInstance, newData: number[]): Updates the chart with new numbers. Returnsvoid.
Your Task:
Create a declaration file easy-chart.d.ts that defines the following:
- A
ChartInstanceinterface (give it a simple property likeid: string). - The
initChartfunction with the correct parameter and return types. - The
updateDatafunction with the correct parameter and return types.
Ensure you wrap your definitions in a declare module 'easy-chart' block so TypeScript recognizes it as a module declaration.
There are no comments for now.