Skip to content

Commit 5940379

Browse files
committed
Add serialization of typenode for null/undefined/never as part of metadata type
Fixes #12684 and #11933
1 parent e3925db commit 5940379

File tree

6 files changed

+253
-15
lines changed

6 files changed

+253
-15
lines changed

src/compiler/transformers/ts.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,8 @@ namespace ts {
16621662

16631663
switch (node.kind) {
16641664
case SyntaxKind.VoidKeyword:
1665+
case SyntaxKind.UndefinedKeyword:
1666+
case SyntaxKind.NullKeyword:
16651667
return createVoidZero();
16661668

16671669
case SyntaxKind.ParenthesizedType:
@@ -1715,27 +1717,35 @@ namespace ts {
17151717
case SyntaxKind.UnionType:
17161718
{
17171719
const unionOrIntersection = <UnionOrIntersectionTypeNode>node;
1718-
let serializedUnion: Identifier;
1720+
let serializedUnion: Identifier | VoidExpression;
17191721
for (const typeNode of unionOrIntersection.types) {
1720-
const serializedIndividual = serializeTypeNode(typeNode) as Identifier;
1721-
// Non identifier
1722-
if (serializedIndividual.kind !== SyntaxKind.Identifier) {
1723-
serializedUnion = undefined;
1724-
break;
1725-
}
1722+
const serializedIndividual = serializeTypeNode(typeNode);
17261723

1727-
// One of the individual is global object, return immediately
1728-
if (serializedIndividual.text === "Object") {
1729-
return serializedIndividual;
1730-
}
1724+
if (isIdentifier(serializedIndividual)) {
1725+
// One of the individual is global object, return immediately
1726+
if (serializedIndividual.text === "Object") {
1727+
return serializedIndividual;
1728+
}
1729+
1730+
// Different types
1731+
if (serializedUnion && isIdentifier(serializedUnion) && serializedUnion.text !== serializedIndividual.text) {
1732+
serializedUnion = undefined;
1733+
break;
1734+
}
17311735

1732-
// Different types
1733-
if (serializedUnion && serializedUnion.text !== serializedIndividual.text) {
1736+
serializedUnion = serializedIndividual;
1737+
}
1738+
else if (isVoidExpression(serializedIndividual)) {
1739+
// If we dont have any other type already set, set the initial type
1740+
if (!serializedUnion) {
1741+
serializedUnion = serializedIndividual;
1742+
}
1743+
}
1744+
else {
1745+
// Non identifier and undefined/null
17341746
serializedUnion = undefined;
17351747
break;
17361748
}
1737-
1738-
serializedUnion = serializedIndividual;
17391749
}
17401750

17411751
// If we were able to find common type
@@ -1751,6 +1761,7 @@ namespace ts {
17511761
case SyntaxKind.TypeLiteral:
17521762
case SyntaxKind.AnyKeyword:
17531763
case SyntaxKind.ThisType:
1764+
case SyntaxKind.NeverKeyword:
17541765
break;
17551766

17561767
default:

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,6 +3581,10 @@ namespace ts {
35813581
return node.kind === SyntaxKind.Identifier;
35823582
}
35833583

3584+
export function isVoidExpression(node: Node): node is VoidExpression {
3585+
return node.kind === SyntaxKind.VoidExpression;
3586+
}
3587+
35843588
export function isGeneratedIdentifier(node: Node): node is GeneratedIdentifier {
35853589
// Using `>` here catches both `GeneratedIdentifierKind.None` and `undefined`.
35863590
return isIdentifier(node) && node.autoGenerateKind > GeneratedIdentifierKind.None;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//// [metadataOfUnionWithNull.ts]
2+
function PropDeco(target: Object, propKey: string | symbol) { }
3+
4+
class A {
5+
}
6+
7+
class B {
8+
@PropDeco
9+
x: "foo" | null;
10+
11+
@PropDeco
12+
y: true | never;
13+
14+
@PropDeco
15+
z: "foo" | undefined;
16+
17+
@PropDeco
18+
a: null;
19+
20+
@PropDeco
21+
b: never;
22+
23+
@PropDeco
24+
c: undefined;
25+
26+
@PropDeco
27+
d: undefined | null;
28+
}
29+
30+
//// [metadataOfUnionWithNull.js]
31+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
32+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
33+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
34+
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;
35+
return c > 3 && r && Object.defineProperty(target, key, r), r;
36+
};
37+
var __metadata = (this && this.__metadata) || function (k, v) {
38+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
39+
};
40+
function PropDeco(target, propKey) { }
41+
var A = (function () {
42+
function A() {
43+
}
44+
return A;
45+
}());
46+
var B = (function () {
47+
function B() {
48+
}
49+
return B;
50+
}());
51+
__decorate([
52+
PropDeco,
53+
__metadata("design:type", String)
54+
], B.prototype, "x");
55+
__decorate([
56+
PropDeco,
57+
__metadata("design:type", Object)
58+
], B.prototype, "y");
59+
__decorate([
60+
PropDeco,
61+
__metadata("design:type", String)
62+
], B.prototype, "z");
63+
__decorate([
64+
PropDeco,
65+
__metadata("design:type", void 0)
66+
], B.prototype, "a");
67+
__decorate([
68+
PropDeco,
69+
__metadata("design:type", Object)
70+
], B.prototype, "b");
71+
__decorate([
72+
PropDeco,
73+
__metadata("design:type", void 0)
74+
], B.prototype, "c");
75+
__decorate([
76+
PropDeco,
77+
__metadata("design:type", void 0)
78+
], B.prototype, "d");
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/compiler/metadataOfUnionWithNull.ts ===
2+
function PropDeco(target: Object, propKey: string | symbol) { }
3+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
4+
>target : Symbol(target, Decl(metadataOfUnionWithNull.ts, 0, 18))
5+
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
6+
>propKey : Symbol(propKey, Decl(metadataOfUnionWithNull.ts, 0, 33))
7+
8+
class A {
9+
>A : Symbol(A, Decl(metadataOfUnionWithNull.ts, 0, 63))
10+
}
11+
12+
class B {
13+
>B : Symbol(B, Decl(metadataOfUnionWithNull.ts, 3, 1))
14+
15+
@PropDeco
16+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
17+
18+
x: "foo" | null;
19+
>x : Symbol(B.x, Decl(metadataOfUnionWithNull.ts, 5, 9))
20+
21+
@PropDeco
22+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
23+
24+
y: true | never;
25+
>y : Symbol(B.y, Decl(metadataOfUnionWithNull.ts, 7, 20))
26+
27+
@PropDeco
28+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
29+
30+
z: "foo" | undefined;
31+
>z : Symbol(B.z, Decl(metadataOfUnionWithNull.ts, 10, 20))
32+
33+
@PropDeco
34+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
35+
36+
a: null;
37+
>a : Symbol(B.a, Decl(metadataOfUnionWithNull.ts, 13, 25))
38+
39+
@PropDeco
40+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
41+
42+
b: never;
43+
>b : Symbol(B.b, Decl(metadataOfUnionWithNull.ts, 16, 12))
44+
45+
@PropDeco
46+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
47+
48+
c: undefined;
49+
>c : Symbol(B.c, Decl(metadataOfUnionWithNull.ts, 19, 13))
50+
51+
@PropDeco
52+
>PropDeco : Symbol(PropDeco, Decl(metadataOfUnionWithNull.ts, 0, 0))
53+
54+
d: undefined | null;
55+
>d : Symbol(B.d, Decl(metadataOfUnionWithNull.ts, 22, 17))
56+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
=== tests/cases/compiler/metadataOfUnionWithNull.ts ===
2+
function PropDeco(target: Object, propKey: string | symbol) { }
3+
>PropDeco : (target: Object, propKey: string | symbol) => void
4+
>target : Object
5+
>Object : Object
6+
>propKey : string | symbol
7+
8+
class A {
9+
>A : A
10+
}
11+
12+
class B {
13+
>B : B
14+
15+
@PropDeco
16+
>PropDeco : (target: Object, propKey: string | symbol) => void
17+
18+
x: "foo" | null;
19+
>x : "foo"
20+
>null : null
21+
22+
@PropDeco
23+
>PropDeco : (target: Object, propKey: string | symbol) => void
24+
25+
y: true | never;
26+
>y : true
27+
>true : true
28+
29+
@PropDeco
30+
>PropDeco : (target: Object, propKey: string | symbol) => void
31+
32+
z: "foo" | undefined;
33+
>z : "foo"
34+
35+
@PropDeco
36+
>PropDeco : (target: Object, propKey: string | symbol) => void
37+
38+
a: null;
39+
>a : null
40+
>null : null
41+
42+
@PropDeco
43+
>PropDeco : (target: Object, propKey: string | symbol) => void
44+
45+
b: never;
46+
>b : never
47+
48+
@PropDeco
49+
>PropDeco : (target: Object, propKey: string | symbol) => void
50+
51+
c: undefined;
52+
>c : undefined
53+
54+
@PropDeco
55+
>PropDeco : (target: Object, propKey: string | symbol) => void
56+
57+
d: undefined | null;
58+
>d : null
59+
>null : null
60+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
function PropDeco(target: Object, propKey: string | symbol) { }
4+
5+
class A {
6+
}
7+
8+
class B {
9+
@PropDeco
10+
x: "foo" | null;
11+
12+
@PropDeco
13+
y: true | never;
14+
15+
@PropDeco
16+
z: "foo" | undefined;
17+
18+
@PropDeco
19+
a: null;
20+
21+
@PropDeco
22+
b: never;
23+
24+
@PropDeco
25+
c: undefined;
26+
27+
@PropDeco
28+
d: undefined | null;
29+
}

0 commit comments

Comments
 (0)