-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
False error TS4094: ... exported class expression may not be private or protected. #30355
Comments
The error message didn't accidently write itself... exported anonymous classes can't have private or protected members if declaration emit is enabled, because there's no way to represent that in a .d.ts file. |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
It is possible to use private in declaration files. In my project, for example, I found a lot of them in node_modules folder: export declare class Formatter extends AbstractFormatter {
static metadata: IFormatterMetadata;
format(failures: RuleFailure[]): string;
private escapeXml; <- HERE
} |
I think this is an issue, too. |
Perhaps we should extend d.ts to handle this case then. Ideally the declarations file and the ts source file would be 100% compatible. |
It is currently not possible to generate declaration files when using a class mixin pattern, even if that pattern would otherwise compile and type-check just fine. It would be nice to have support for this 🙏 |
Shouldn't this issue be open? |
In particular, it'd be nice to be able to do something like function foo<T>(arg: T): SomeType<T> { ... }
type Bar = {num: number}
type FooBar = ReturnType<typeof foo<Bar>> I get what you're saying, that This is valid: type FooBar = ReturnType<typeof foo> But in that example, TypeScript sets the type of Basically, it just intuitively seems like there should be some way to pass a generic arg there, but we can't, and TypeScript automatically sticks |
If a function type FooBar = ReturnType<(typeof foo)<Bar>> That would be a breaking change to TypeScript though. |
Please see #35822 |
I re-opened this at #36060 |
Interesting fix: Moving the mixin to its own file and doing a type Constructor<T = {}> = new (...args: any[]) => T
export default <T extends Constructor>(base: T) => class SomeClass extends base {
protected something: boolean = false
} While a named export throws the error: type Constructor<T = {}> = new (...args: any[]) => T
export const mixin = <T extends Constructor>(base: T) => class SomeClass extends base {
protected something: boolean = false
} |
here is how you can fix it, instead of function makeClass() {
return class {
private x = 0;
public y = 1;
}
} do type PublicConstructor<T> = new () => T;
interface MyPublicInterface {
y: number;
}
function makeClass(): PublicConstructor<MyPublicInterface> {
return class {
private x = 0;
public y = 1;
}
} |
@cdata not exactly! :) see the prior workaround the OP pointed to:
In the case of a mixin function (which is exactly the problem I had here too), that means you need to return the union ( So, if your mixin class is resulting in a union of interface i.e class A & B , then your mixin function should return something like You can come up with various ways to shorten this notation using generic type templates. I can post some helper code and type utilities for this if there is interest. I agree this isn't a bug per-se. The type-declaration just expects your mixin function to return types explicitely that it actually can express i.e export in a d.ts, and in this case that will mean explicitely declaring the resulting mixin interface outside of the mixin function so that it can be used as a return type of it. EDIT and yes, that is in fact the previous answer here explained in words :D |
Solution: Just give the function a proper return type declaration. This one then needs to be an indirect connection, e.g. an interface describing the prototype of the returned class. Then, the compiler stops complaining :) |
Another solution can be to just use the ES2020 private fields if you ever encounter this problem. This will avoid you to define a return type, which can be annoying if your mixin is quite complex : function makeClass() {
return class {
#x = 0;
public y = 1;
}
} |
Just play with Omit type 😎. Just a example with vitest : import { vi as _vi } from 'vitest';
type VitestUtils = Omit<
typeof _vi,
'_timers' | '_mockedDate' | '_mocker' | 'getImporter' | '_config' // never also works fine
>;
type Primitive = number | boolean | string;
type Props = {
[key in string]?:
| Primitive
| Primitive[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| ((this: VitestUtils, ...args: any) => any);
};
export default function extendVitest<T extends Props>(options: T) {
return Object.assign(_vi as VitestUtils, options);
} NB: If you don't know the private members of the class, just put never as second parameter of Omit. |
Same thing with "constant class".
Interestingly Using workaround:
|
Although use |
you can write like this
|
it would be great if ESlint rule will be already aware. I had some error and quick fix was generation of private _data + get/set data methods. And it was throwing errors. Replacing with # helped to solve it. |
isn't it a bug then? So it's doing exactly same, but with two files instead of one. I'm quite surprised to see that this issue is Closed while indeed it must not and should be fixed |
…mns (#1587) # Pull Request ## 🤨 Rationale Resolves #1211 In Angular, we didn't have a solution for the code duplication that came with multiple columns being fractional width and groupable. This PR creates mixins for fractional width columns and groupable columns to reduce the amount of duplication. There is still the potential for future code reduction within the tests, but I decided that coming up to a solution single-sourcing more of our test code was out of scope for this PR. ## 👩💻 Implementation - Create `mixinFractionalWidthColumnAPI` function that allows a `NimbleTableColumnBaseDirective` to claim support for being fractional width (i.e. inputs for `fractionalWidth` and `minPixelWidth`). This function is exported from the existing `@ni/nimble-angular/table-column` entry point. - Create `mixinGroupableColumnAPI` function that allows a `NimbleTableColumnBaseDirective` to claim support for being groupable (i.e. inputs for `groupIndex` and `groupingDisabled`). This function is exported from the existing `@ni/nimble-angular/table-column` entry point. - Update existing table columns to use these new mixins - These changes required making `renderer` and `elementRef` public (though marked as internal) in `NimbleTableColumnBaseDirective` because otherwise TS error 4094 is triggered. This is related to the `mixinFractionalWidthColumnAPI` and `mixinGroupableColumnAPI` functions having an implicit return type and that inferred type including `NimbleTableColumnBaseDirective`. [The scenario I was hitting is described in this TypeScript issue](microsoft/TypeScript#30355). ## 🧪 Testing - Verified existing unit tests are passing - Verified Angular example app still works as expected ## ✅ Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj <[email protected]>
TypeScript Version: 3.3.3333
Code
src/test.ts:
tsconfig.json:
Expected behavior:
No compilation error.
Actual behavior:
Compiler prints error:
$ tsc
src/test.ts(1,17): error TS4094: Property 'privateMember' of exported class expression may not be private or protected.
Playground Link: not possible to provide.
Workaround
Declare the return type explicitly:
The text was updated successfully, but these errors were encountered: