Skip to content

Commit 3d4f5c9

Browse files
fix: failure on anonymous class with a method (backport #1824) (#1846)
# Backport This will backport the following commits from `main` to `maintenance/v5.6`: - [fix: failure on anonymous class with a method (#1824)](#1824) <!--- Backport version: 9.5.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Rico Hermans <[email protected]>
1 parent 1840c41 commit 3d4f5c9

File tree

5 files changed

+155
-17
lines changed

5 files changed

+155
-17
lines changed

fixtures/jsii-calc/lib/decorators.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
type Constructor = { new (...args: any[]): {} };
2+
3+
export function functionReturnsClasstype<T extends Constructor>(ctr: T) {
4+
return class extends ctr {
5+
};
6+
}
7+
8+
/**
9+
* A class decorator that changes inherited state and adds a readonly field to the class.
10+
*
11+
* This wasn't the thing that was exploding, see `function-returning-anonymous-class.ts` for that.
12+
* Nevertheless, this makes for a good class decorator demo.
13+
*/
14+
export function classDecorator(x: typeof SomeDecoratedClass): typeof SomeDecoratedClass {
15+
const ret = class extends x {
16+
constructor() {
17+
super();
18+
this.state = this.state + this.state;
19+
}
20+
};
21+
22+
// This adds a field to the class, but we can't reflect that in the type because of the limitations
23+
// of decorators. That's we advertise it through interface merging below.
24+
(ret.prototype as any)['field'] = 'some_added_field';
25+
26+
return ret;
27+
}
28+
29+
@classDecorator
30+
export class SomeDecoratedClass {
31+
protected state = 'state';
32+
33+
public accessState() {
34+
return this.state;
35+
}
36+
}
37+
38+
export interface SomeDecoratedClass {
39+
readonly field: string;
40+
}
41+
42+
/**
43+
* Exercise the above code
44+
*/
45+
function tryDecoratedClass() {
46+
const instance = new SomeDecoratedClass();
47+
return instance.field;
48+
}
49+
// Suppress unused locals warnings
50+
void tryDecoratedClass;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
type Constructor = { new (...args: any[]): {} };
2+
3+
/**
4+
* Just the mere presence of this function is enough to break jsii, even if it's not exported from
5+
* the jsii root module.
6+
*
7+
* The reason is that when we add deprecation warnings we visit all functions in all files.
8+
*/
9+
export function propertyInjectionDecorator<T extends Constructor>(ctr: T) {
10+
// Important for the bug: the anonymous class extends something, *and*
11+
// declares a method.
12+
return class extends ctr {
13+
public someMethod(): string {
14+
return 'abc';
15+
}
16+
};
17+
}

fixtures/jsii-calc/lib/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export * from './stability';
99
export * from './submodules';
1010
export * from './container-types';
1111
export * from './indirect-implementation';
12+
export * from './decorators';
1213

1314
export * as submodule from './submodule';
1415
export * as onlystatic from './only-static';

src/common/symbol-id.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ interface SymbolIdOptions {
4949
*/
5050
export function symbolIdentifier(
5151
typeChecker: ts.TypeChecker,
52-
sym: ts.Symbol,
52+
sym: ts.Symbol | undefined,
5353
options: SymbolIdOptions = {},
5454
): string | undefined {
55+
if (!sym) {
56+
return undefined;
57+
}
58+
5559
// If this symbol happens to be an alias, resolve it first
5660
// eslint-disable-next-line no-bitwise
5761
while ((sym.flags & ts.SymbolFlags.Alias) !== 0) {

test/__snapshots__/integration.test.ts.snap

+82-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)