Skip to content

Commit de0e475

Browse files
authored
Recreate old decorator metadata behavior (microsoft#19089)
* Emulate pre 2.4 metadata behavior of eliding null and undefined from unions without strictNullChecks * Accept baseline * Update comment * Update for second old baseline * Respect strict
1 parent 98f04e6 commit de0e475

File tree

7 files changed

+99
-11
lines changed

7 files changed

+99
-11
lines changed

src/compiler/transformers/ts.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace ts {
4545

4646
const resolver = context.getEmitResolver();
4747
const compilerOptions = context.getCompilerOptions();
48+
const strictNullChecks = typeof compilerOptions.strictNullChecks === "undefined" ? compilerOptions.strict : compilerOptions.strictNullChecks;
4849
const languageVersion = getEmitScriptTarget(compilerOptions);
4950
const moduleKind = getEmitModuleKind(compilerOptions);
5051

@@ -1869,7 +1870,16 @@ namespace ts {
18691870
// Note when updating logic here also update getEntityNameForDecoratorMetadata
18701871
// so that aliases can be marked as referenced
18711872
let serializedUnion: SerializedTypeNode;
1872-
for (const typeNode of node.types) {
1873+
for (let typeNode of node.types) {
1874+
while (typeNode.kind === SyntaxKind.ParenthesizedType) {
1875+
typeNode = (typeNode as ParenthesizedTypeNode).type; // Skip parens if need be
1876+
}
1877+
if (typeNode.kind === SyntaxKind.NeverKeyword) {
1878+
continue; // Always elide `never` from the union/intersection if possible
1879+
}
1880+
if (!strictNullChecks && (typeNode.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) {
1881+
continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks
1882+
}
18731883
const serializedIndividual = serializeTypeNode(typeNode);
18741884

18751885
if (isIdentifier(serializedIndividual) && serializedIndividual.escapedText === "Object") {
@@ -1893,7 +1903,7 @@ namespace ts {
18931903
}
18941904

18951905
// If we were able to find common type, use it
1896-
return serializedUnion;
1906+
return serializedUnion || createVoidZero(); // Fallback is only hit if all union constituients are null/undefined/never
18971907
}
18981908

18991909
/**
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [decoratorMetadataNoStrictNull.ts]
2+
const dec = (obj: {}, prop: string) => undefined
3+
4+
class Foo {
5+
@dec public foo: string | null;
6+
@dec public bar: string;
7+
}
8+
9+
//// [decoratorMetadataNoStrictNull.js]
10+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13+
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;
14+
return c > 3 && r && Object.defineProperty(target, key, r), r;
15+
};
16+
var __metadata = (this && this.__metadata) || function (k, v) {
17+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
18+
};
19+
var dec = function (obj, prop) { return undefined; };
20+
var Foo = /** @class */ (function () {
21+
function Foo() {
22+
}
23+
__decorate([
24+
dec,
25+
__metadata("design:type", String)
26+
], Foo.prototype, "foo");
27+
__decorate([
28+
dec,
29+
__metadata("design:type", String)
30+
], Foo.prototype, "bar");
31+
return Foo;
32+
}());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/decoratorMetadataNoStrictNull.ts ===
2+
const dec = (obj: {}, prop: string) => undefined
3+
>dec : Symbol(dec, Decl(decoratorMetadataNoStrictNull.ts, 0, 5))
4+
>obj : Symbol(obj, Decl(decoratorMetadataNoStrictNull.ts, 0, 13))
5+
>prop : Symbol(prop, Decl(decoratorMetadataNoStrictNull.ts, 0, 21))
6+
>undefined : Symbol(undefined)
7+
8+
class Foo {
9+
>Foo : Symbol(Foo, Decl(decoratorMetadataNoStrictNull.ts, 0, 48))
10+
11+
@dec public foo: string | null;
12+
>dec : Symbol(dec, Decl(decoratorMetadataNoStrictNull.ts, 0, 5))
13+
>foo : Symbol(Foo.foo, Decl(decoratorMetadataNoStrictNull.ts, 2, 11))
14+
15+
@dec public bar: string;
16+
>dec : Symbol(dec, Decl(decoratorMetadataNoStrictNull.ts, 0, 5))
17+
>bar : Symbol(Foo.bar, Decl(decoratorMetadataNoStrictNull.ts, 3, 33))
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/compiler/decoratorMetadataNoStrictNull.ts ===
2+
const dec = (obj: {}, prop: string) => undefined
3+
>dec : (obj: {}, prop: string) => any
4+
>(obj: {}, prop: string) => undefined : (obj: {}, prop: string) => any
5+
>obj : {}
6+
>prop : string
7+
>undefined : undefined
8+
9+
class Foo {
10+
>Foo : Foo
11+
12+
@dec public foo: string | null;
13+
>dec : (obj: {}, prop: string) => any
14+
>foo : string
15+
>null : null
16+
17+
@dec public bar: string;
18+
>dec : (obj: {}, prop: string) => any
19+
>bar : string
20+
}

tests/baselines/reference/metadataOfClassFromAlias.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var ClassA = /** @class */ (function () {
4343
}
4444
__decorate([
4545
annotation(),
46-
__metadata("design:type", Object)
46+
__metadata("design:type", auxiliry_1.SomeClass)
4747
], ClassA.prototype, "array", void 0);
4848
return ClassA;
4949
}());

tests/baselines/reference/metadataOfUnionWithNull.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ var B = /** @class */ (function () {
6363
}
6464
__decorate([
6565
PropDeco,
66-
__metadata("design:type", Object)
66+
__metadata("design:type", String)
6767
], B.prototype, "x");
6868
__decorate([
6969
PropDeco,
70-
__metadata("design:type", Object)
70+
__metadata("design:type", Boolean)
7171
], B.prototype, "y");
7272
__decorate([
7373
PropDeco,
74-
__metadata("design:type", Object)
74+
__metadata("design:type", String)
7575
], B.prototype, "z");
7676
__decorate([
7777
PropDeco,
@@ -87,27 +87,27 @@ var B = /** @class */ (function () {
8787
], B.prototype, "c");
8888
__decorate([
8989
PropDeco,
90-
__metadata("design:type", Object)
90+
__metadata("design:type", void 0)
9191
], B.prototype, "d");
9292
__decorate([
9393
PropDeco,
94-
__metadata("design:type", Object)
94+
__metadata("design:type", typeof Symbol === "function" ? Symbol : Object)
9595
], B.prototype, "e");
9696
__decorate([
9797
PropDeco,
9898
__metadata("design:type", Object)
9999
], B.prototype, "f");
100100
__decorate([
101101
PropDeco,
102-
__metadata("design:type", Object)
102+
__metadata("design:type", A)
103103
], B.prototype, "g");
104104
__decorate([
105105
PropDeco,
106-
__metadata("design:type", Object)
106+
__metadata("design:type", B)
107107
], B.prototype, "h");
108108
__decorate([
109109
PropDeco,
110-
__metadata("design:type", Object)
110+
__metadata("design:type", typeof Symbol === "function" ? Symbol : Object)
111111
], B.prototype, "j");
112112
return B;
113113
}());
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
const dec = (obj: {}, prop: string) => undefined
4+
5+
class Foo {
6+
@dec public foo: string | null;
7+
@dec public bar: string;
8+
}

0 commit comments

Comments
 (0)