Skip to content

dist/index.d.ts mixes export = with named exports (TS2309, @ts-ignore-d) — breaks consumers under TypeScript 7 / tsgo #441

Description

@Togetic

Summary

consola@3.4.2's legacy declaration entry, dist/index.d.ts, combines an export assignment with
named exports:

declare const consola: ConsolaInstance;

// @ts-ignore
export = consola;
export { ConsolaInstance, ConsolaOptions, consola, createConsola };

That is invalid TypeScript — export = cannot coexist with other exported elements (TS2309) — and the
// @ts-ignore silences the error inside consola's own file. Under tsc this works out: the error is
suppressed and the named exports remain usable, so import { consola } from "consola" type-checks.

Under TypeScript 7 / tsgo it does not. tsgo raises an additional diagnostic at the
consumer's import site:

error TS2595: 'consola' can only be imported by using a default import.

A consumer cannot suppress that — the @ts-ignore lives in consola, and the error is reported in the
importing file. So a correct, documented import becomes an unfixable error for downstream projects.

Why it bites even though exports is correct

The exports map is fine: exports["."].node.import.types → dist/index.d.mts, which does a clean
export { …, consola, createConsola, consola as default }. The problem is only the legacy top-level
types field
→ dist/index.d.ts.

Any consumer whose resolution reaches that legacy entry rather than the exports map gets the invalid
file. That is not exotic: Nuxt generates compilerOptions.paths entries mapping bare package names to
package directories (to pin exact versions in a pnpm workspace), e.g.

"paths": { "consola": ["../../../node_modules/.pnpm/consola@3.4.2/node_modules/consola"] }

Directory resolution consults types/main, not exports — in tsc and tsgo alike (verified with
--traceResolution on both). So in a Nuxt project every import { consola } from "consola" resolves
through the invalid declaration file. We hit this on 8 import sites in a Nuxt 4 monorepo.

Confirmed with a faux package carrying the same shape (invalid legacy index.d.ts + valid
index.d.mts behind an exports map), toggling only the paths entry:

tsconfig tsgo tsc
with paths: { faux: ["./node_modules/faux"] } TS2595 at the consumer clean
without paths (so exports is consulted) clean clean

That isolates it precisely: the exports map is fine and resolving through it is clean on both
compilers. Only the legacy types entry is broken, and it is reachable in real projects.

Suggested fix

Make dist/index.d.ts valid, so the legacy entry is safe for consumers that reach it. Either:

  1. Drop export = consola from dist/index.d.ts and keep only the named + default exports (matching
    index.d.mts); or
  2. If export = must stay for CJS require() consumers, keep it in dist/index.d.cts only — which
    already uses it correctly and on its own — and point the legacy types field at a valid file.

Either removes the need for the // @ts-ignore and makes consola forward-compatible with TypeScript 7
without downstream changes.

Environment

  • consola 3.4.2
  • tsc 5.9.3 — accepts the named import (no diagnostics)
  • tsgo @typescript/native-preview@7.0.0-dev.20260707.2 — TS2595 at each consumer import site
  • Also reproduces via vue-tsc on typescript-native-bridge (tsgo 7.0.2 behind the classic API)
  • moduleResolution: "Bundler", module: "preserve", strict: true

Minimal repro (no consola needed): a 5-line .d.ts with the same export = + named-exports +
@ts-ignore shape, imported by one line, reproduces TS2595 on tsgo and is clean on tsc. Filed
upstream at microsoft/typescript-go as well, since tsgo arguably should not surface a consumer-side
error for a suppressed declaration-side one — but fixing the declaration file resolves it regardless of
what upstream decides.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions