#441·consola

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

Author: TogeticCreated Jul 28, 2026Updated Aug 21, 2026

Summary

[email protected]'s legacy declaration entry, dist/index.d.ts, combines an export assignment with named exports:

typescript
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.typesdist/index.d.mts, which does a clean export { …, consola, createConsola, consola as default }. The problem is only the legacy top-level types fielddist/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.

json
"paths": { "consola": ["../../../node_modules/.pnpm/[email protected]/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/[email protected]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.