Skip to content

Conversation

mtsgrd
Copy link
Contributor

@mtsgrd mtsgrd commented Sep 1, 2025

Problem

When using svelte-package to compile Svelte components that import generic classes from external packages the generated .d.ts files were losing generic type information and falling back to any types.

Example:

// Source: packages/shared/src/lib/routing/webRoutes.svelte.ts
export const WEB_ROUTES_SERVICE = new InjectionToken<WebRoutesService>('WebRoutesService');

// Generated .d.ts (before fix):
export declare const WEB_ROUTES_SERVICE: any; // ❌ Lost generic type

// Generated .d.ts (after fix):
export declare const WEB_ROUTES_SERVICE: InjectionToken<WebRoutesService>; // ✅ Preserves generic type

This issue only occurred with cross-package imports in monorepo environments where the generic class was defined in a separate package from where it was instantiated.

Root Cause

The issue was in emitDts.ts where the TypeScript compiler options used legacy Node10 module resolution (ModuleResolutionKind.Node10). This older resolution strategy cannot properly resolve modern package.json exports fields and workspace dependencies commonly used in monorepo setups, leading to failed module resolution and type inference fallbacks.

Solution

Updated the module resolution:

// Before
moduleResolution:
    // NodeJS: up to 4.9, Node10: since 5.0
    (ts.ModuleResolutionKind as any).NodeJs ?? 
    ts.ModuleResolutionKind.Node10, // Classic if not set, which gives wrong results

// After  
moduleResolution: ts.ModuleResolutionKind.Node16

This change allows the TypeScript compiler to:

  • Properly resolve exports fields in package.json
  • Handle workspace dependencies (workspace:*)
  • Maintain backward compatibility with older TypeScript versions

Testing

Added new test at test/emitDts/samples/cross-package-generic-types/ that:

  • Simulates a monorepo package structure with external generic dependencies
  • Verifies that generic type parameters are preserved in generated .d.ts files
  • Ensures no regression for existing functionality

Update moduleResolution from node10 to node16 to properly resolve generic
types across package boundaries in monorepo setups.

Previously, cross-package generic type information was lost during .d.ts
generation, causing types like `GenericType<T>` to be emitted as `any`.

- Add test case for cross-package generic type preservation
@mtsgrd mtsgrd marked this pull request as ready for review September 1, 2025 19:41
@mtsgrd
Copy link
Contributor Author

mtsgrd commented Sep 2, 2025

I am unsure if the added test is something that needs to be checked in, but it was useful in isolating the root cause of the problem I was experiencing.

@mtsgrd
Copy link
Contributor Author

mtsgrd commented Sep 9, 2025

@dummdidumm this pr is important for any project that compiles a lib to be used by a svelte app. The setup I'm working with has core -> shared -> app, and the declarations for shared fall back to any when there are generics involved. Would you be able to have a look?

@jasonlyu123
Copy link
Member

jasonlyu123 commented Sep 10, 2025

I think it would be better to respect the moduleResolution config in the tsconfig.json. And when the moduleResolution is undefined or classic, it should remain the current default node10. This meant your test workspace should explicitly specify moduleResolution: node16.

@dummdidumm
Copy link
Member

Agree with Jason - I can't push to this so will close an open a separate PR with the changes. Thank you!

@dummdidumm dummdidumm closed this Sep 11, 2025
dummdidumm added a commit that referenced this pull request Sep 11, 2025
dummdidumm added a commit that referenced this pull request Sep 11, 2025
see #2837 for more info

---------

Co-authored-by: Mattias Granlund <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants