Skip to content

TypeScript: CustomTypeOptions.resources doesn't compose across monorepo packages #2409

Description

@adrai

Problem

In monorepo setups where packages are consumed as source (no separate build step), the leaf app's CustomTypeOptions.resources module augmentation must include all namespaces from all dependencies — even ones it never uses directly in its own code.

This is because CustomTypeOptions uses global module augmentation via declare module "i18next", and there's only one resources declaration for the entire app. Each package cannot independently declare just its own namespace types.

Example

Given a turborepo with:

  • apps/frontend (Next.js app)
  • packages/ui (shared component library with its own @repo/ui namespace)

For example: The frontend's augs.d.ts here must declare the UI package's namespace too, even though it never uses it directly:

declare module "i18next" {
  interface CustomTypeOptions {
    resources: {
      // Frontend's own namespaces — properly typed
      common: typeof common;
      "page-home": typeof pageHome;
      // ...

      // Dependency namespace — forced to use `any` as a bandaid
      "@repo/ui": any;
    };
  }
}

Without this, TypeScript errors on useTranslation("@repo/ui") calls inside the UI package code that the frontend consumes.

Current workaround

Declare dependency namespaces as any. This works but loses type safety for those cross-package namespaces.

Why TypeScript project references don't help

Potential directions

No concrete proposal yet — this issue tracks the limitation and collects ideas. Some possibilities:

  • Per-package type declarations that merge automatically
  • A generic parameter on hooks to scope type context per package
  • Build-time tooling to generate a merged augmentation file
  • A composable type helper utility

Context

Discussed in #1604

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions