Description
Before You File a Bug Report Please Confirm You Have Done The Following...
- I have tried restarting my IDE and the issue persists.
- I have updated to the latest version of the packages.
- I have searched for related issues and found none that matched my issue.
- I have read the FAQ and my problem is not listed.
Issue Description
Take the Error
class. As far as I can tell, TypeScript differentiates between the runtime name Error
, which is an ErrorConstructor
that you call new
on, versus the type name Error
, which is what is returned by the ErrorConstructor
in the type system:
const error: Error = new Error()
Where the name Error
is simultaneously the TypeScript type and the runtime object.
Suppose I want to decorate subclasses of Error
on the fly:
/* eslint-disable @typescript-eslint/no-explicit-any */
function decorateErrorClass<T extends new (...args: any[]) => Error>(
errorConstructor: T
) {
const decoratedConstructor = errorConstructor as T & {
additionalStaticProp: boolean;
};
decoratedConstructor.additionalStaticProp = true;
return { MyError: decoratedConstructor };
}
const { MyError } = decorateErrorClass(
class MyError extends Error {
panic() {
console.log('panicking!');
}
}
);
/**
* Some commentary that should be exported.
*/
export type MyError = InstanceType<typeof MyError>;
// AFAICT if we don't export the instance type of MyError (above), DX degrades for importers
export { MyError };
// MyError (class) and myError (instance) are both correctly typed in this file.
const myError = new MyError();
console.log(MyError.additionalStaticProp); // true
myError.panic(); // outputs: "panicking!"
And then, in some other file, I attempt to import and export MyError
:
import { MyError } from './index.js';
export type SomethingElse = boolean;
export { MyError };
npx eslint
gives the following error:
npx eslint
/tmp/tmp.1UuL6fdCYx/src/1-broken/bad.ts
5:1 error All exports in the declaration are only used as types. Use `export type` @typescript-eslint/consistent-type-exports
✖ 1 problem (1 error, 0 warnings)
1 error and 0 warnings potentially fixable with the `--fix` option.
What makes this false positive particularly pernicious is if I'm blindly applying --fix
on the file I'm editing (as I am wont to do), it'll turn that MyError
runtime export into a type-only export. This breaks downstream consumers at runtime but the linter shows no issues.
My best guess: the issue is with the self-described "hack" on line 154. I'd dig further, but the workaround in my case is easy and elegant enough:
- const { MyError } = decorateErrorClass(
+ export const { MyError } = decorateErrorClass(
class MyError extends Error {
panic() {
console.log('panicking!');
}
}
);
/**
* Some commentary that should be exported.
*/
export type MyError = InstanceType<typeof MyError>;
- export { MyError };
Maybe related to #10313.
Reproduction Repository Link
https://github.com/Xunnamius/typescript-eslint-bug-repro-11388
Repro Steps
- clone the repo
npm install
npx eslint
Versions
package | version |
---|---|
typescript-eslint |
8.36.0 |
@eslint/js |
9.30.1 |
TypeScript |
5.8.3 |
ESLint |
9.30.1 |
node |
22.17.0 |