Skip to content

Commit

Permalink
Merge pull request #28609 from ajafff/class-decorator-generics
Browse files Browse the repository at this point in the history
resolve TypeReference in class decorator at parent of class
  • Loading branch information
rbuckton committed Mar 19, 2019
2 parents a0f122b + 12ef619 commit cfb0ade
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -1474,7 +1474,14 @@ namespace ts {
// @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method.
// }
//
if (location.parent && isClassElement(location.parent)) {

// class Decorators are resolved outside of the class to avoid referencing type parameters of that class.
//
// type T = number;
// declare function y(x: T): any;
// @param(1 as T) // <-- T should resolve to the type alias outside of class C
// class C<T> {}
if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) {
location = location.parent;
}
break;
Expand Down
35 changes: 35 additions & 0 deletions tests/baselines/reference/decoratorReferences.js
@@ -0,0 +1,35 @@
//// [decoratorReferences.ts]
declare function y(...args: any[]): any;
type T = number;
@y(1 as T, C) // <-- T should be resolved to the type alias, not the type parameter of the class; C should resolve to the class
class C<T> {
@y(null as T) // <-- y should resolve to the function declaration, not the parameter; T should resolve to the type parameter of the class
method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
}

//// [decoratorReferences.js]
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var C = /** @class */ (function () {
function C() {
}
C_1 = C;
C.prototype.method = function (x, y) { }; // <-- decorator y should be resolved at the class declaration, not the parameter.
var C_1;
__decorate([
y(null) // <-- y should resolve to the function declaration, not the parameter; T should resolve to the type parameter of the class
,
__param(0, y)
], C.prototype, "method");
C = C_1 = __decorate([
y(1, C_1) // <-- T should be resolved to the type alias, not the type parameter of the class; C should resolve to the class
], C);
return C;
}());
27 changes: 27 additions & 0 deletions tests/baselines/reference/decoratorReferences.symbols
@@ -0,0 +1,27 @@
=== tests/cases/compiler/decoratorReferences.ts ===
declare function y(...args: any[]): any;
>y : Symbol(y, Decl(decoratorReferences.ts, 0, 0))
>args : Symbol(args, Decl(decoratorReferences.ts, 0, 19))

type T = number;
>T : Symbol(T, Decl(decoratorReferences.ts, 0, 40))

@y(1 as T, C) // <-- T should be resolved to the type alias, not the type parameter of the class; C should resolve to the class
>y : Symbol(y, Decl(decoratorReferences.ts, 0, 0))
>T : Symbol(T, Decl(decoratorReferences.ts, 0, 40))
>C : Symbol(C, Decl(decoratorReferences.ts, 1, 16))

class C<T> {
>C : Symbol(C, Decl(decoratorReferences.ts, 1, 16))
>T : Symbol(T, Decl(decoratorReferences.ts, 3, 8))

@y(null as T) // <-- y should resolve to the function declaration, not the parameter; T should resolve to the type parameter of the class
>y : Symbol(y, Decl(decoratorReferences.ts, 0, 0))
>T : Symbol(T, Decl(decoratorReferences.ts, 3, 8))

method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
>method : Symbol(C.method, Decl(decoratorReferences.ts, 3, 12))
>y : Symbol(y, Decl(decoratorReferences.ts, 0, 0))
>x : Symbol(x, Decl(decoratorReferences.ts, 5, 11))
>y : Symbol(y, Decl(decoratorReferences.ts, 5, 16))
}
30 changes: 30 additions & 0 deletions tests/baselines/reference/decoratorReferences.types
@@ -0,0 +1,30 @@
=== tests/cases/compiler/decoratorReferences.ts ===
declare function y(...args: any[]): any;
>y : (...args: any[]) => any
>args : any[]

type T = number;
>T : number

@y(1 as T, C) // <-- T should be resolved to the type alias, not the type parameter of the class; C should resolve to the class
>y(1 as T, C) : any
>y : (...args: any[]) => any
>1 as T : number
>1 : 1
>C : typeof C

class C<T> {
>C : C<T>

@y(null as T) // <-- y should resolve to the function declaration, not the parameter; T should resolve to the type parameter of the class
>y(null as T) : any
>y : (...args: any[]) => any
>null as T : T
>null : null

method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
>method : (x: any, y: any) => void
>y : (...args: any[]) => any
>x : any
>y : any
}
9 changes: 9 additions & 0 deletions tests/cases/compiler/decoratorReferences.ts
@@ -0,0 +1,9 @@
// @experimentalDecorators: true

declare function y(...args: any[]): any;
type T = number;
@y(1 as T, C) // <-- T should be resolved to the type alias, not the type parameter of the class; C should resolve to the class
class C<T> {
@y(null as T) // <-- y should resolve to the function declaration, not the parameter; T should resolve to the type parameter of the class
method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
}

0 comments on commit cfb0ade

Please sign in to comment.