TypeScript: CustomTypeOptions.resources doesn't compose across monorepo packages
#2.409 aberto em 22 de mar. de 2026
Métricas do repositório
- Stars
- (7.194 estrelas)
- Métricas de merge de PR
- (Mesclagem média 2h 18m) (3 fundiu PRs em 30d)
Description
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/uinamespace)
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
- Composite configs are not supported by Next.js
- Turborepo advises against using them
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 https://github.com/i18next/i18next/discussions/1604