@@ -1637,6 +1637,8 @@ namespace ts {
16371637 return createVoidZero ( ) ;
16381638 }
16391639
1640+ type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression ;
1641+
16401642 /**
16411643 * Serializes a type node for use with decorator type metadata.
16421644 *
@@ -1655,7 +1657,7 @@ namespace ts {
16551657 *
16561658 * @param node The type node to serialize.
16571659 */
1658- function serializeTypeNode ( node : TypeNode ) : Expression {
1660+ function serializeTypeNode ( node : TypeNode ) : SerializedTypeNode {
16591661 if ( node === undefined ) {
16601662 return createIdentifier ( "Object" ) ;
16611663 }
@@ -1664,6 +1666,7 @@ namespace ts {
16641666 case SyntaxKind . VoidKeyword :
16651667 case SyntaxKind . UndefinedKeyword :
16661668 case SyntaxKind . NullKeyword :
1669+ case SyntaxKind . NeverKeyword :
16671670 return createVoidZero ( ) ;
16681671
16691672 case SyntaxKind . ParenthesizedType :
@@ -1715,53 +1718,15 @@ namespace ts {
17151718
17161719 case SyntaxKind . IntersectionType :
17171720 case SyntaxKind . UnionType :
1718- {
1719- const unionOrIntersection = < UnionOrIntersectionTypeNode > node ;
1720- let serializedUnion : Identifier | VoidExpression ;
1721- for ( const typeNode of unionOrIntersection . types ) {
1722- const serializedIndividual = serializeTypeNode ( typeNode ) ;
1723-
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- }
1735-
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
1746- serializedUnion = undefined ;
1747- break ;
1748- }
1749- }
1721+ return serializeUnionOrIntersectionType ( < UnionOrIntersectionTypeNode > node ) ;
17501722
1751- // If we were able to find common type
1752- if ( serializedUnion ) {
1753- return serializedUnion ;
1754- }
1755- }
1756- // Fallthrough
17571723 case SyntaxKind . TypeQuery :
17581724 case SyntaxKind . TypeOperator :
17591725 case SyntaxKind . IndexedAccessType :
17601726 case SyntaxKind . MappedType :
17611727 case SyntaxKind . TypeLiteral :
17621728 case SyntaxKind . AnyKeyword :
17631729 case SyntaxKind . ThisType :
1764- case SyntaxKind . NeverKeyword :
17651730 break ;
17661731
17671732 default :
@@ -1772,13 +1737,48 @@ namespace ts {
17721737 return createIdentifier ( "Object" ) ;
17731738 }
17741739
1740+ function serializeUnionOrIntersectionType ( node : UnionOrIntersectionTypeNode ) : SerializedTypeNode {
1741+ let serializedUnion : SerializedTypeNode ;
1742+ for ( const typeNode of node . types ) {
1743+ const serializedIndividual = serializeTypeNode ( typeNode ) ;
1744+
1745+ if ( isVoidExpression ( serializedIndividual ) ) {
1746+ // If we dont have any other type already set, set the initial type
1747+ if ( ! serializedUnion ) {
1748+ serializedUnion = serializedIndividual ;
1749+ }
1750+ }
1751+ else if ( isIdentifier ( serializedIndividual ) && serializedIndividual . text === "Object" ) {
1752+ // One of the individual is global object, return immediately
1753+ return serializedIndividual ;
1754+ }
1755+ // If there exists union that is not void 0 expression, check if the the common type is identifier.
1756+ // anything more complex and we will just default to Object
1757+ else if ( serializedUnion && ! isVoidExpression ( serializedUnion ) ) {
1758+ // Different types
1759+ if ( ! isIdentifier ( serializedUnion ) ||
1760+ ! isIdentifier ( serializedIndividual ) ||
1761+ serializedUnion . text !== serializedIndividual . text ) {
1762+ return createIdentifier ( "Object" ) ;
1763+ }
1764+ }
1765+ else {
1766+ // Initialize the union type
1767+ serializedUnion = serializedIndividual ;
1768+ }
1769+ }
1770+
1771+ // If we were able to find common type, use it
1772+ return serializedUnion ;
1773+ }
1774+
17751775 /**
17761776 * Serializes a TypeReferenceNode to an appropriate JS constructor value for use with
17771777 * decorator type metadata.
17781778 *
17791779 * @param node The type reference node.
17801780 */
1781- function serializeTypeReferenceNode ( node : TypeReferenceNode ) {
1781+ function serializeTypeReferenceNode ( node : TypeReferenceNode ) : SerializedTypeNode {
17821782 switch ( resolver . getTypeReferenceSerializationKind ( node . typeName , currentScope ) ) {
17831783 case TypeReferenceSerializationKind . Unknown :
17841784 const serialized = serializeEntityNameAsExpression ( node . typeName , /*useFallback*/ true ) ;
@@ -1826,14 +1826,15 @@ namespace ts {
18261826 }
18271827 }
18281828
1829+ type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression ;
18291830 /**
18301831 * Serializes an entity name as an expression for decorator type metadata.
18311832 *
18321833 * @param node The entity name to serialize.
18331834 * @param useFallback A value indicating whether to use logical operators to test for the
18341835 * entity name at runtime.
18351836 */
1836- function serializeEntityNameAsExpression ( node : EntityName , useFallback : boolean ) : Expression {
1837+ function serializeEntityNameAsExpression ( node : EntityName , useFallback : boolean ) : SerializedEntityNameAsExpression {
18371838 switch ( node . kind ) {
18381839 case SyntaxKind . Identifier :
18391840 // Create a clone of the name with a new parent, and treat it as if it were
@@ -1866,8 +1867,8 @@ namespace ts {
18661867 * @param useFallback A value indicating whether to use logical operators to test for the
18671868 * qualified name at runtime.
18681869 */
1869- function serializeQualifiedNameAsExpression ( node : QualifiedName , useFallback : boolean ) : Expression {
1870- let left : Expression ;
1870+ function serializeQualifiedNameAsExpression ( node : QualifiedName , useFallback : boolean ) : PropertyAccessExpression {
1871+ let left : SerializedEntityNameAsExpression ;
18711872 if ( node . left . kind === SyntaxKind . Identifier ) {
18721873 left = serializeEntityNameAsExpression ( node . left , useFallback ) ;
18731874 }
@@ -1892,7 +1893,7 @@ namespace ts {
18921893 * Gets an expression that points to the global "Symbol" constructor at runtime if it is
18931894 * available.
18941895 */
1895- function getGlobalSymbolNameWithFallback ( ) : Expression {
1896+ function getGlobalSymbolNameWithFallback ( ) : ConditionalExpression {
18961897 return createConditional (
18971898 createTypeCheck ( createIdentifier ( "Symbol" ) , "function" ) ,
18981899 createIdentifier ( "Symbol" ) ,
0 commit comments