From e042fec3b59b2bc36a07bcd8b433c1aedde1db29 Mon Sep 17 00:00:00 2001 From: Andrei L <1881266+unrevised6419@users.noreply.github.com> Date: Thu, 24 Sep 2026 16:11:17 +0300 Subject: [PATCH] fix(packages): declare `@types/react` as an optional peer dependency (#4892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `lucide-react` and `lucide-react-native` both ship `.d.ts` files that import React types (`ForwardRefExoticComponent`, `SVGProps`, `RefAttributes`, `ReactNode`), but neither package declares `@types/react`. Under a hoisted `node_modules` this resolves by accident, so the gap is invisible in normal testing. It does not resolve under a strict layout — most notably pnpm's global virtual store (`enableGlobalVirtualStore`), where each package is linked from a store path outside the consuming repo. TypeScript resolves a package's imports relative to where that package physically lives and ignores `NODE_PATH`, so `react` resolves to the untyped `react/index.js`. Every icon's props silently degrade to `any`, and consumers hit implicit-any errors on their own callbacks under `noImplicitAny`. `skipLibCheck: true` hides the errors inside the `.d.ts` itself, which is why this survives most typechecks. Declaring the typings package as a peer dependency (rather than a hard dependency) lets it dedupe against whatever `@types/react` the consumer already has. `peerDependenciesMeta` marks it optional so JS-only consumers get no unmet-peer warning. Verified by packing each package and installing the tarball into a scratch consumer with `pnpm --virtual-store-dir` pointing outside the consumer, then typechecking with `skipLibCheck: false` and a `@ts-expect-error` probe on a nonexistent icon prop — a positive type assertion keeps passing when types widen to `any`, so it would not catch a regression. Before the change the probe reports `TS2578: Unused '@ts-expect-error' directive` plus `TS7016` inside the shipped `.d.ts`; after it, `tsc` is clean and `--traceResolution` shows `react` resolving to `@types/react/index.d.ts` instead of `react/index.js`. Existing peer ranges are unchanged and the lockfile is unaffected. Co-authored-by: Claude Opus 5 Co-authored-by: Eric Fennis --- packages/lucide-react-native/package.json | 6 ++++++ packages/lucide-react/package.json | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/lucide-react-native/package.json b/packages/lucide-react-native/package.json index c68e8566c..77160b65f 100644 --- a/packages/lucide-react-native/package.json +++ b/packages/lucide-react-native/package.json @@ -85,8 +85,14 @@ "vite": "^7.3.6" }, "peerDependencies": { + "@types/react": "*", "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-native": "*", "react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } } diff --git a/packages/lucide-react/package.json b/packages/lucide-react/package.json index 38bf3c8ea..a7775a4a8 100644 --- a/packages/lucide-react/package.json +++ b/packages/lucide-react/package.json @@ -68,6 +68,12 @@ "vite": "^7.3.6" }, "peerDependencies": { + "@types/react": "*", "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }