diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac45866e2d..ea44fb0f3b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 {} + if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { location = location.parent; } break; diff --git a/tests/baselines/reference/decoratorReferences.js b/tests/baselines/reference/decoratorReferences.js new file mode 100644 index 0000000000..6189cfc52c --- /dev/null +++ b/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 { + @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; +}()); diff --git a/tests/baselines/reference/decoratorReferences.symbols b/tests/baselines/reference/decoratorReferences.symbols new file mode 100644 index 0000000000..d018367e07 --- /dev/null +++ b/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 { +>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)) +} diff --git a/tests/baselines/reference/decoratorReferences.types b/tests/baselines/reference/decoratorReferences.types new file mode 100644 index 0000000000..14a9f9e667 --- /dev/null +++ b/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 { +>C : C + + @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 +} diff --git a/tests/cases/compiler/decoratorReferences.ts b/tests/cases/compiler/decoratorReferences.ts new file mode 100644 index 0000000000..c6222e67fd --- /dev/null +++ b/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 { + @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. +} \ No newline at end of file