mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-02 14:48:32 -05:00
mark types used in decorator metadata as referenced (#12890)
This commit is contained in:
@@ -16581,6 +16581,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getParameterTypeNodeForDecoratorCheck(node: ParameterDeclaration): TypeNode {
|
||||
return node.dotDotDotToken ? getRestParameterElementType(node.type) : node.type;
|
||||
}
|
||||
|
||||
/** Check the decorators of a node */
|
||||
function checkDecorators(node: Node): void {
|
||||
if (!node.decorators) {
|
||||
@@ -16612,7 +16616,7 @@ namespace ts {
|
||||
const constructor = getFirstConstructorWithBody(<ClassDeclaration>node);
|
||||
if (constructor) {
|
||||
for (const parameter of constructor.parameters) {
|
||||
markTypeNodeAsReferenced(parameter.type);
|
||||
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -16621,15 +16625,17 @@ namespace ts {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
for (const parameter of (<FunctionLikeDeclaration>node).parameters) {
|
||||
markTypeNodeAsReferenced(parameter.type);
|
||||
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
|
||||
}
|
||||
|
||||
markTypeNodeAsReferenced((<FunctionLikeDeclaration>node).type);
|
||||
break;
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
markTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(<ParameterDeclaration>node));
|
||||
break;
|
||||
case SyntaxKind.Parameter:
|
||||
markTypeNodeAsReferenced((<PropertyDeclaration | ParameterDeclaration>node).type);
|
||||
markTypeNodeAsReferenced((<PropertyDeclaration>node).type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1577,24 +1577,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the most likely element type for a TypeNode. This is not an exhaustive test
|
||||
* as it assumes a rest argument can only be an array type (either T[], or Array<T>).
|
||||
*
|
||||
* @param node The type node.
|
||||
*/
|
||||
function getRestParameterElementType(node: TypeNode) {
|
||||
if (node && node.kind === SyntaxKind.ArrayType) {
|
||||
return (<ArrayTypeNode>node).elementType;
|
||||
}
|
||||
else if (node && node.kind === SyntaxKind.TypeReference) {
|
||||
return singleOrUndefined((<TypeReferenceNode>node).typeArguments);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the types of the parameters of a node for use with decorator type metadata.
|
||||
*
|
||||
|
||||
@@ -803,6 +803,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the most likely element type for a TypeNode. This is not an exhaustive test
|
||||
* as it assumes a rest argument can only be an array type (either T[], or Array<T>).
|
||||
*
|
||||
* @param node The type node.
|
||||
*/
|
||||
export function getRestParameterElementType(node: TypeNode) {
|
||||
if (node && node.kind === SyntaxKind.ArrayType) {
|
||||
return (<ArrayTypeNode>node).elementType;
|
||||
}
|
||||
else if (node && node.kind === SyntaxKind.TypeReference) {
|
||||
return singleOrUndefined((<TypeReferenceNode>node).typeArguments);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function isVariableLike(node: Node): node is VariableLikeDeclaration {
|
||||
if (node) {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
//// [tests/cases/compiler/decoratorMetadataRestParameterWithImportedType.ts] ////
|
||||
|
||||
//// [aux.ts]
|
||||
|
||||
export class SomeClass {
|
||||
field: string;
|
||||
}
|
||||
|
||||
//// [aux1.ts]
|
||||
export class SomeClass1 {
|
||||
field: string;
|
||||
}
|
||||
|
||||
//// [aux2.ts]
|
||||
export class SomeClass2 {
|
||||
field: string;
|
||||
}
|
||||
//// [main.ts]
|
||||
import { SomeClass } from './aux';
|
||||
import { SomeClass1 } from './aux1';
|
||||
|
||||
function annotation(): ClassDecorator {
|
||||
return (target: any): void => { };
|
||||
}
|
||||
|
||||
function annotation1(): MethodDecorator {
|
||||
return (target: any): void => { };
|
||||
}
|
||||
|
||||
@annotation()
|
||||
export class ClassA {
|
||||
array: SomeClass[];
|
||||
|
||||
constructor(...init: SomeClass[]) {
|
||||
this.array = init;
|
||||
}
|
||||
|
||||
@annotation1()
|
||||
foo(... args: SomeClass1[]) {
|
||||
}
|
||||
}
|
||||
|
||||
//// [aux.js]
|
||||
"use strict";
|
||||
var SomeClass = (function () {
|
||||
function SomeClass() {
|
||||
}
|
||||
return SomeClass;
|
||||
}());
|
||||
exports.SomeClass = SomeClass;
|
||||
//// [aux1.js]
|
||||
"use strict";
|
||||
var SomeClass1 = (function () {
|
||||
function SomeClass1() {
|
||||
}
|
||||
return SomeClass1;
|
||||
}());
|
||||
exports.SomeClass1 = SomeClass1;
|
||||
//// [aux2.js]
|
||||
"use strict";
|
||||
var SomeClass2 = (function () {
|
||||
function SomeClass2() {
|
||||
}
|
||||
return SomeClass2;
|
||||
}());
|
||||
exports.SomeClass2 = SomeClass2;
|
||||
//// [main.js]
|
||||
"use strict";
|
||||
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 __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var aux_1 = require("./aux");
|
||||
var aux1_1 = require("./aux1");
|
||||
function annotation() {
|
||||
return function (target) { };
|
||||
}
|
||||
function annotation1() {
|
||||
return function (target) { };
|
||||
}
|
||||
var ClassA = (function () {
|
||||
function ClassA() {
|
||||
var init = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
init[_i] = arguments[_i];
|
||||
}
|
||||
this.array = init;
|
||||
}
|
||||
ClassA.prototype.foo = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
};
|
||||
return ClassA;
|
||||
}());
|
||||
__decorate([
|
||||
annotation1(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [aux1_1.SomeClass1]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], ClassA.prototype, "foo", null);
|
||||
ClassA = __decorate([
|
||||
annotation(),
|
||||
__metadata("design:paramtypes", [aux_1.SomeClass])
|
||||
], ClassA);
|
||||
exports.ClassA = ClassA;
|
||||
@@ -0,0 +1,77 @@
|
||||
=== tests/cases/compiler/aux.ts ===
|
||||
|
||||
export class SomeClass {
|
||||
>SomeClass : Symbol(SomeClass, Decl(aux.ts, 0, 0))
|
||||
|
||||
field: string;
|
||||
>field : Symbol(SomeClass.field, Decl(aux.ts, 1, 24))
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/aux1.ts ===
|
||||
export class SomeClass1 {
|
||||
>SomeClass1 : Symbol(SomeClass1, Decl(aux1.ts, 0, 0))
|
||||
|
||||
field: string;
|
||||
>field : Symbol(SomeClass1.field, Decl(aux1.ts, 0, 25))
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/aux2.ts ===
|
||||
export class SomeClass2 {
|
||||
>SomeClass2 : Symbol(SomeClass2, Decl(aux2.ts, 0, 0))
|
||||
|
||||
field: string;
|
||||
>field : Symbol(SomeClass2.field, Decl(aux2.ts, 0, 25))
|
||||
}
|
||||
=== tests/cases/compiler/main.ts ===
|
||||
import { SomeClass } from './aux';
|
||||
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
|
||||
|
||||
import { SomeClass1 } from './aux1';
|
||||
>SomeClass1 : Symbol(SomeClass1, Decl(main.ts, 1, 8))
|
||||
|
||||
function annotation(): ClassDecorator {
|
||||
>annotation : Symbol(annotation, Decl(main.ts, 1, 36))
|
||||
>ClassDecorator : Symbol(ClassDecorator, Decl(lib.d.ts, --, --))
|
||||
|
||||
return (target: any): void => { };
|
||||
>target : Symbol(target, Decl(main.ts, 4, 12))
|
||||
}
|
||||
|
||||
function annotation1(): MethodDecorator {
|
||||
>annotation1 : Symbol(annotation1, Decl(main.ts, 5, 1))
|
||||
>MethodDecorator : Symbol(MethodDecorator, Decl(lib.d.ts, --, --))
|
||||
|
||||
return (target: any): void => { };
|
||||
>target : Symbol(target, Decl(main.ts, 8, 12))
|
||||
}
|
||||
|
||||
@annotation()
|
||||
>annotation : Symbol(annotation, Decl(main.ts, 1, 36))
|
||||
|
||||
export class ClassA {
|
||||
>ClassA : Symbol(ClassA, Decl(main.ts, 9, 1))
|
||||
|
||||
array: SomeClass[];
|
||||
>array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
|
||||
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
|
||||
|
||||
constructor(...init: SomeClass[]) {
|
||||
>init : Symbol(init, Decl(main.ts, 15, 16))
|
||||
>SomeClass : Symbol(SomeClass, Decl(main.ts, 0, 8))
|
||||
|
||||
this.array = init;
|
||||
>this.array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
|
||||
>this : Symbol(ClassA, Decl(main.ts, 9, 1))
|
||||
>array : Symbol(ClassA.array, Decl(main.ts, 12, 21))
|
||||
>init : Symbol(init, Decl(main.ts, 15, 16))
|
||||
}
|
||||
|
||||
@annotation1()
|
||||
>annotation1 : Symbol(annotation1, Decl(main.ts, 5, 1))
|
||||
|
||||
foo(... args: SomeClass1[]) {
|
||||
>foo : Symbol(ClassA.foo, Decl(main.ts, 17, 5))
|
||||
>args : Symbol(args, Decl(main.ts, 20, 8))
|
||||
>SomeClass1 : Symbol(SomeClass1, Decl(main.ts, 1, 8))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
=== tests/cases/compiler/aux.ts ===
|
||||
|
||||
export class SomeClass {
|
||||
>SomeClass : SomeClass
|
||||
|
||||
field: string;
|
||||
>field : string
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/aux1.ts ===
|
||||
export class SomeClass1 {
|
||||
>SomeClass1 : SomeClass1
|
||||
|
||||
field: string;
|
||||
>field : string
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/aux2.ts ===
|
||||
export class SomeClass2 {
|
||||
>SomeClass2 : SomeClass2
|
||||
|
||||
field: string;
|
||||
>field : string
|
||||
}
|
||||
=== tests/cases/compiler/main.ts ===
|
||||
import { SomeClass } from './aux';
|
||||
>SomeClass : typeof SomeClass
|
||||
|
||||
import { SomeClass1 } from './aux1';
|
||||
>SomeClass1 : typeof SomeClass1
|
||||
|
||||
function annotation(): ClassDecorator {
|
||||
>annotation : () => ClassDecorator
|
||||
>ClassDecorator : ClassDecorator
|
||||
|
||||
return (target: any): void => { };
|
||||
>(target: any): void => { } : (target: any) => void
|
||||
>target : any
|
||||
}
|
||||
|
||||
function annotation1(): MethodDecorator {
|
||||
>annotation1 : () => MethodDecorator
|
||||
>MethodDecorator : MethodDecorator
|
||||
|
||||
return (target: any): void => { };
|
||||
>(target: any): void => { } : (target: any) => void
|
||||
>target : any
|
||||
}
|
||||
|
||||
@annotation()
|
||||
>annotation() : ClassDecorator
|
||||
>annotation : () => ClassDecorator
|
||||
|
||||
export class ClassA {
|
||||
>ClassA : ClassA
|
||||
|
||||
array: SomeClass[];
|
||||
>array : SomeClass[]
|
||||
>SomeClass : SomeClass
|
||||
|
||||
constructor(...init: SomeClass[]) {
|
||||
>init : SomeClass[]
|
||||
>SomeClass : SomeClass
|
||||
|
||||
this.array = init;
|
||||
>this.array = init : SomeClass[]
|
||||
>this.array : SomeClass[]
|
||||
>this : this
|
||||
>array : SomeClass[]
|
||||
>init : SomeClass[]
|
||||
}
|
||||
|
||||
@annotation1()
|
||||
>annotation1() : MethodDecorator
|
||||
>annotation1 : () => MethodDecorator
|
||||
|
||||
foo(... args: SomeClass1[]) {
|
||||
>foo : (...args: SomeClass1[]) => void
|
||||
>args : SomeClass1[]
|
||||
>SomeClass1 : SomeClass1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// @experimentalDecorators: true
|
||||
// @emitDecoratorMetadata: true
|
||||
// @target: es5
|
||||
|
||||
// @filename: aux.ts
|
||||
export class SomeClass {
|
||||
field: string;
|
||||
}
|
||||
|
||||
// @filename: aux1.ts
|
||||
export class SomeClass1 {
|
||||
field: string;
|
||||
}
|
||||
|
||||
// @filename: aux2.ts
|
||||
export class SomeClass2 {
|
||||
field: string;
|
||||
}
|
||||
// @filename: main.ts
|
||||
import { SomeClass } from './aux';
|
||||
import { SomeClass1 } from './aux1';
|
||||
|
||||
function annotation(): ClassDecorator {
|
||||
return (target: any): void => { };
|
||||
}
|
||||
|
||||
function annotation1(): MethodDecorator {
|
||||
return (target: any): void => { };
|
||||
}
|
||||
|
||||
@annotation()
|
||||
export class ClassA {
|
||||
array: SomeClass[];
|
||||
|
||||
constructor(...init: SomeClass[]) {
|
||||
this.array = init;
|
||||
}
|
||||
|
||||
@annotation1()
|
||||
foo(... args: SomeClass1[]) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user