Skip to content

Commit e5e1533

Browse files
authored
mark types used in decorator metadata as referenced (#12890)
1 parent c76a3a6 commit e5e1533

File tree

7 files changed

+339
-21
lines changed

7 files changed

+339
-21
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16581,6 +16581,10 @@ namespace ts {
1658116581
}
1658216582
}
1658316583

16584+
function getParameterTypeNodeForDecoratorCheck(node: ParameterDeclaration): TypeNode {
16585+
return node.dotDotDotToken ? getRestParameterElementType(node.type) : node.type;
16586+
}
16587+
1658416588
/** Check the decorators of a node */
1658516589
function checkDecorators(node: Node): void {
1658616590
if (!node.decorators) {
@@ -16612,7 +16616,7 @@ namespace ts {
1661216616
const constructor = getFirstConstructorWithBody(<ClassDeclaration>node);
1661316617
if (constructor) {
1661416618
for (const parameter of constructor.parameters) {
16615-
markTypeNodeAsReferenced(parameter.type);
16619+
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
1661616620
}
1661716621
}
1661816622
break;
@@ -16621,15 +16625,17 @@ namespace ts {
1662116625
case SyntaxKind.GetAccessor:
1662216626
case SyntaxKind.SetAccessor:
1662316627
for (const parameter of (<FunctionLikeDeclaration>node).parameters) {
16624-
markTypeNodeAsReferenced(parameter.type);
16628+
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
1662516629
}
1662616630

1662716631
markTypeNodeAsReferenced((<FunctionLikeDeclaration>node).type);
1662816632
break;
1662916633

1663016634
case SyntaxKind.PropertyDeclaration:
16635+
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(<ParameterDeclaration>node));
16636+
break;
1663116637
case SyntaxKind.Parameter:
16632-
markTypeNodeAsReferenced((<PropertyDeclaration | ParameterDeclaration>node).type);
16638+
markTypeNodeAsReferenced((<PropertyDeclaration>node).type);
1663316639
break;
1663416640
}
1663516641
}

src/compiler/transformers/ts.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,24 +1577,6 @@ namespace ts {
15771577
}
15781578
}
15791579

1580-
/**
1581-
* Gets the most likely element type for a TypeNode. This is not an exhaustive test
1582-
* as it assumes a rest argument can only be an array type (either T[], or Array<T>).
1583-
*
1584-
* @param node The type node.
1585-
*/
1586-
function getRestParameterElementType(node: TypeNode) {
1587-
if (node && node.kind === SyntaxKind.ArrayType) {
1588-
return (<ArrayTypeNode>node).elementType;
1589-
}
1590-
else if (node && node.kind === SyntaxKind.TypeReference) {
1591-
return singleOrUndefined((<TypeReferenceNode>node).typeArguments);
1592-
}
1593-
else {
1594-
return undefined;
1595-
}
1596-
}
1597-
15981580
/**
15991581
* Serializes the types of the parameters of a node for use with decorator type metadata.
16001582
*

src/compiler/utilities.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,23 @@ namespace ts {
803803
}
804804
}
805805

806+
/**
807+
* Gets the most likely element type for a TypeNode. This is not an exhaustive test
808+
* as it assumes a rest argument can only be an array type (either T[], or Array<T>).
809+
*
810+
* @param node The type node.
811+
*/
812+
export function getRestParameterElementType(node: TypeNode) {
813+
if (node && node.kind === SyntaxKind.ArrayType) {
814+
return (<ArrayTypeNode>node).elementType;
815+
}
816+
else if (node && node.kind === SyntaxKind.TypeReference) {
817+
return singleOrUndefined((<TypeReferenceNode>node).typeArguments);
818+
}
819+
else {
820+
return undefined;
821+
}
822+
}
806823

807824
export function isVariableLike(node: Node): node is VariableLikeDeclaration {
808825
if (node) {
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//// [tests/cases/compiler/decoratorMetadataRestParameterWithImportedType.ts] ////
2+
3+
//// [aux.ts]
4+
5+
export class SomeClass {
6+
field: string;
7+
}
8+
9+
//// [aux1.ts]
10+
export class SomeClass1 {
11+
field: string;
12+
}
13+
14+
//// [aux2.ts]
15+
export class SomeClass2 {
16+
field: string;
17+
}
18+
//// [main.ts]
19+
import { SomeClass } from './aux';
20+
import { SomeClass1 } from './aux1';
21+
22+
function annotation(): ClassDecorator {
23+
return (target: any): void => { };
24+
}
25+
26+
function annotation1(): MethodDecorator {
27+
return (target: any): void => { };
28+
}
29+
30+
@annotation()
31+
export class ClassA {
32+
array: SomeClass[];
33+
34+
constructor(...init: SomeClass[]) {
35+
this.array = init;
36+
}
37+
38+
@annotation1()
39+
foo(... args: SomeClass1[]) {
40+
}
41+
}
42+
43+
//// [aux.js]
44+
"use strict";
45+
var SomeClass = (function () {
46+
function SomeClass() {
47+
}
48+
return SomeClass;
49+
}());
50+
exports.SomeClass = SomeClass;
51+
//// [aux1.js]
52+
"use strict";
53+
var SomeClass1 = (function () {
54+
function SomeClass1() {
55+
}
56+
return SomeClass1;
57+
}());
58+
exports.SomeClass1 = SomeClass1;
59+
//// [aux2.js]
60+
"use strict";
61+
var SomeClass2 = (function () {
62+
function SomeClass2() {
63+
}
64+
return SomeClass2;
65+
}());
66+
exports.SomeClass2 = SomeClass2;
67+
//// [main.js]
68+
"use strict";
69+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
70+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
71+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
72+
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;
73+
return c > 3 && r && Object.defineProperty(target, key, r), r;
74+
};
75+
var __metadata = (this && this.__metadata) || function (k, v) {
76+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
77+
};
78+
var aux_1 = require("./aux");
79+
var aux1_1 = require("./aux1");
80+
function annotation() {
81+
return function (target) { };
82+
}
83+
function annotation1() {
84+
return function (target) { };
85+
}
86+
var ClassA = (function () {
87+
function ClassA() {
88+
var init = [];
89+
for (var _i = 0; _i < arguments.length; _i++) {
90+
init[_i] = arguments[_i];
91+
}
92+
this.array = init;
93+
}
94+
ClassA.prototype.foo = function () {
95+
var args = [];
96+
for (var _i = 0; _i < arguments.length; _i++) {
97+
args[_i] = arguments[_i];
98+
}
99+
};
100+
return ClassA;
101+
}());
102+
__decorate([
103+
annotation1(),
104+
__metadata("design:type", Function),
105+
__metadata("design:paramtypes", [aux1_1.SomeClass1]),
106+
__metadata("design:returntype", void 0)
107+
], ClassA.prototype, "foo", null);
108+
ClassA = __decorate([
109+
annotation(),
110+
__metadata("design:paramtypes", [aux_1.SomeClass])
111+
], ClassA);
112+
exports.ClassA = ClassA;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
=== tests/cases/compiler/aux.ts ===
2+
3+
export class SomeClass {
4+
>SomeClass : Symbol(SomeClass, Decl(aux.ts, 0, 0))
5+
6+
field: string;
7+
>field : Symbol(SomeClass.field, Decl(aux.ts, 1, 24))
8+
}
9+
10+
=== tests/cases/compiler/aux1.ts ===
11+
export class SomeClass1 {
12+
>SomeClass1 : Symbol(SomeClass1, Decl(aux1.ts, 0, 0))
13+
14+
field: string;
15+
>field : Symbol(SomeClass1.field, Decl(aux1.ts, 0, 25))
16+
}
17+
18+
=== tests/cases/compiler/aux2.ts ===
19+
export class SomeClass2 {
20+
>SomeClass2 : Symbol(SomeClass2, Decl(aux2.ts, 0, 0))
21+
22+
field: string;
23+
>field : Symbol(SomeClass2.field, Decl(aux2.ts, 0, 25))
24+
}
25+
=== tests/cases/compiler/main.ts ===
26+
import { SomeClass } from './aux';
27+
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
28+
29+
import { SomeClass1 } from './aux1';
30+
>SomeClass1 : Symbol(SomeClass1, Decl(main.ts, 1, 8))
31+
32+
function annotation(): ClassDecorator {
33+
>annotation : Symbol(annotation, Decl(main.ts, 1, 36))
34+
>ClassDecorator : Symbol(ClassDecorator, Decl(lib.d.ts, --, --))
35+
36+
return (target: any): void => { };
37+
>target : Symbol(target, Decl(main.ts, 4, 12))
38+
}
39+
40+
function annotation1(): MethodDecorator {
41+
>annotation1 : Symbol(annotation1, Decl(main.ts, 5, 1))
42+
>MethodDecorator : Symbol(MethodDecorator, Decl(lib.d.ts, --, --))
43+
44+
return (target: any): void => { };
45+
>target : Symbol(target, Decl(main.ts, 8, 12))
46+
}
47+
48+
@annotation()
49+
>annotation : Symbol(annotation, Decl(main.ts, 1, 36))
50+
51+
export class ClassA {
52+
>ClassA : Symbol(ClassA, Decl(main.ts, 9, 1))
53+
54+
array: SomeClass[];
55+
>array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
56+
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
57+
58+
constructor(...init: SomeClass[]) {
59+
>init : Symbol(init, Decl(main.ts, 15, 16))
60+
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
61+
62+
this.array = init;
63+
>this.array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
64+
>this : Symbol(ClassA, Decl(main.ts, 9, 1))
65+
>array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
66+
>init : Symbol(init, Decl(main.ts, 15, 16))
67+
}
68+
69+
@annotation1()
70+
>annotation1 : Symbol(annotation1, Decl(main.ts, 5, 1))
71+
72+
foo(... args: SomeClass1[]) {
73+
>foo : Symbol(ClassA.foo, Decl(main.ts, 17, 5))
74+
>args : Symbol(args, Decl(main.ts, 20, 8))
75+
>SomeClass1 : Symbol(SomeClass1, Decl(main.ts, 1, 8))
76+
}
77+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
=== tests/cases/compiler/aux.ts ===
2+
3+
export class SomeClass {
4+
>SomeClass : SomeClass
5+
6+
field: string;
7+
>field : string
8+
}
9+
10+
=== tests/cases/compiler/aux1.ts ===
11+
export class SomeClass1 {
12+
>SomeClass1 : SomeClass1
13+
14+
field: string;
15+
>field : string
16+
}
17+
18+
=== tests/cases/compiler/aux2.ts ===
19+
export class SomeClass2 {
20+
>SomeClass2 : SomeClass2
21+
22+
field: string;
23+
>field : string
24+
}
25+
=== tests/cases/compiler/main.ts ===
26+
import { SomeClass } from './aux';
27+
>SomeClass : typeof SomeClass
28+
29+
import { SomeClass1 } from './aux1';
30+
>SomeClass1 : typeof SomeClass1
31+
32+
function annotation(): ClassDecorator {
33+
>annotation : () => ClassDecorator
34+
>ClassDecorator : ClassDecorator
35+
36+
return (target: any): void => { };
37+
>(target: any): void => { } : (target: any) => void
38+
>target : any
39+
}
40+
41+
function annotation1(): MethodDecorator {
42+
>annotation1 : () => MethodDecorator
43+
>MethodDecorator : MethodDecorator
44+
45+
return (target: any): void => { };
46+
>(target: any): void => { } : (target: any) => void
47+
>target : any
48+
}
49+
50+
@annotation()
51+
>annotation() : ClassDecorator
52+
>annotation : () => ClassDecorator
53+
54+
export class ClassA {
55+
>ClassA : ClassA
56+
57+
array: SomeClass[];
58+
>array : SomeClass[]
59+
>SomeClass : SomeClass
60+
61+
constructor(...init: SomeClass[]) {
62+
>init : SomeClass[]
63+
>SomeClass : SomeClass
64+
65+
this.array = init;
66+
>this.array = init : SomeClass[]
67+
>this.array : SomeClass[]
68+
>this : this
69+
>array : SomeClass[]
70+
>init : SomeClass[]
71+
}
72+
73+
@annotation1()
74+
>annotation1() : MethodDecorator
75+
>annotation1 : () => MethodDecorator
76+
77+
foo(... args: SomeClass1[]) {
78+
>foo : (...args: SomeClass1[]) => void
79+
>args : SomeClass1[]
80+
>SomeClass1 : SomeClass1
81+
}
82+
}

0 commit comments

Comments
 (0)