Summary
tsdown emits declarations for tersify that cause downstream consumers to fail with TS2742 during declaration emit, while tsc declarations from the same source tree do not.
This repro is preserved in a private staging repo with a submodule pointing at a dedicated tersify branch:
cyberuni/tsdown-ts2742-repro
- submodule branch:
cyberuni/tsdown-types-export-regression
Repro
From tersify/packages/tersify:
pnpm smoke:consumer:tsdown
pnpm smoke:consumer:tsc
Current result:
pnpm smoke:consumer:tsdown fails
pnpm smoke:consumer:tsc passes
Downstream consumer
import { tersible } from 'tersify'
export function foo() {
return tersible((x: any) => !!x)
}
Consumer tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"emitDeclarationOnly": true,
"strict": true,
"skipLibCheck": false
}
}
Error
index.ts(3,17): error TS2742: The inferred type of 'foo' cannot be named without a reference to './node_modules/tersify/esm/types.mjs'. This is likely not portable. A type annotation is necessary.
Important constraint
The tersify source files are the same in both cases.
Only the emitted declarations differ.
Narrowed cause
The issue is not caused by:
- the
source condition in package.json
.mjs alone
- root
index re-export shape alone
tersible.d.mts alone
The decisive difference is the emitted shape of esm/types.d.mts.
This emitted pattern fails downstream:
type TersifyOptions = ...
type Tersible<T = unknown> = ...
export { Tersible, TersifyOptions }
This also fails:
type TersifyOptions = ...
type Tersible<T = unknown> = ...
export type { Tersible, TersifyOptions }
This passes:
export type TersifyOptions = ...
export type Tersible<T = unknown> = ...
Working hypothesis
When tsdown emits a declaration file with public types as local aliases plus a trailing export list, TypeScript 5.0 does not treat those symbols as a portable public origin during downstream inference of exported return types.
In this case that leads to TS2742, while direct exported type declarations do not.
Environment
Verified in this setup:
- Host OS: Ubuntu 24.04.3 LTS
- Kernel: Linux 6.6.114.1-microsoft-standard-WSL2
- Architecture: x64
- Node: v22.21.1
- pnpm: 10.33.4
- npm: 10.9.4
Package under test:
- tersify: 4.0.0
- tsdown: 0.22.0
- package-local typescript: 6.0.2
Downstream consumer used in the smoke repro:
Notes
The downstream repro intentionally installs typescript@5.0.2 in the consumer project, because that is the compiler producing the reported TS2742.
So there are two TypeScript versions involved:
tersify package devDependency: 6.0.2
- downstream consumer compiler: 5.0.2
The current repro was verified on WSL2 / Ubuntu, but the issue appears to be driven by emitted declaration shape rather than the host OS itself.
Summary
tsdownemits declarations fortersifythat cause downstream consumers to fail withTS2742during declaration emit, whiletscdeclarations from the same source tree do not.This repro is preserved in a private staging repo with a submodule pointing at a dedicated
tersifybranch:cyberuni/tsdown-ts2742-reprocyberuni/tsdown-types-export-regressionRepro
From
tersify/packages/tersify:Current result:
pnpm smoke:consumer:tsdownfailspnpm smoke:consumer:tscpassesDownstream consumer
Consumer
tsconfig.json:{ "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "NodeNext", "declaration": true, "emitDeclarationOnly": true, "strict": true, "skipLibCheck": false } }Error
Important constraint
The
tersifysource files are the same in both cases.Only the emitted declarations differ.
Narrowed cause
The issue is not caused by:
sourcecondition inpackage.json.mjsaloneindexre-export shape alonetersible.d.mtsaloneThe decisive difference is the emitted shape of
esm/types.d.mts.This emitted pattern fails downstream:
This also fails:
This passes:
Working hypothesis
When
tsdownemits a declaration file with public types as local aliases plus a trailing export list, TypeScript 5.0 does not treat those symbols as a portable public origin during downstream inference of exported return types.In this case that leads to
TS2742, while direct exported type declarations do not.Environment
Verified in this setup:
Package under test:
Downstream consumer used in the smoke repro:
Notes
The downstream repro intentionally installs
typescript@5.0.2in the consumer project, because that is the compiler producing the reportedTS2742.So there are two TypeScript versions involved:
tersifypackage devDependency: 6.0.2The current repro was verified on WSL2 / Ubuntu, but the issue appears to be driven by emitted declaration shape rather than the host OS itself.