DEV Community

Jody Heavener
Jody Heavener

Posted on

A tip on using peer dependencies with TypeScript

I encountered this issue recently and felt pretty silly when I realized the simple mistake I was making, so allow me to share, in hopes that it saves someone else time...

When you're developing an NPM package that makes use of a dependency also used by the main application, you might consider listing it as a peer dependency.

Take this example, where we move React from "dependencies" to "peerDependencies":

-  "dependencies": {
-    "react": "^16.8.4 || ^17.0.0"
-  },
   "devDependencies": {
     "@docusaurus/theme-classic": "^2.0.1",
     "@types/react": "^18.0.17"
+  },
+  "peerDependencies": {
+    "react": "^16.8.4 || ^17.0.0"
   }
Enter fullscreen mode Exit fullscreen mode

React is now a peer dependency, which means the main application needs to list it in its own dependencies. Additionally, we're able to keep developing this package with no issues from TypeScript (can you see why?).

Now notice that other package, @docusaurus/theme-classic. I wanted to make this one a peer dependency as well, so I did just that:

   "devDependencies": {
-    "@docusaurus/theme-classic": "^2.0.1",
     "@types/react": "^18.0.17"
   },
   "peerDependencies": {
+    "@docusaurus/theme-classic": "^2.0.1",
     "react": "^16.8.4 || ^17.0.0"
   }
 }
Enter fullscreen mode Exit fullscreen mode

But after I made this change, TypeScript wasn't happy. 😔 When I tried importing from that module I got the typical "Cannot find module or its corresponding type declarations" error. I spent quite a while scratching my head, trying to understand peer dependencies. I knew package manager CLIs don't automatically install peer dependencies, but I couldn't figure out why other packages, such as React, were working while this one wasn't.

And this is where I felt silly after figuring it out: the @docusaurus/theme-classic package was supplying its own type declarations, so moving it over to peer dependencies was eliminating its types altogether.

To address this, the simplest solution I've found is to duplicate that dependency over to "devDependencies". Doing this makes sure that it is installed locally while you develop the package, while also maintaining its status as a peer dependency when the main application consumes it.

   "devDependencies": {
+    "@docusaurus/theme-classic": "^2.0.1",
     "@types/react": "^18.0.17"
   },
   "peerDependencies": {
Enter fullscreen mode Exit fullscreen mode

I've also tried playing with the install-peers package, that claims to install all your peer dependencies as dev dependencies, but wasn't having much success with it.

If you have your own solution for this problem, I'd love to hear it!

Top comments (2)

Collapse
 
vijaystcb profile image
Vijay Thirugnanam

Very nice article. Helped me understand my problem better.

Collapse
 
mxro profile image
Max Rohde

Encountered the same issue! Anyone has any ideas how to work around it?