@@ -1555,12 +1555,15 @@ namespace ts {
15551555 return false ;
15561556 }
15571557
1558+ type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression ;
1559+ type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression ;
1560+
15581561 /**
15591562 * Serializes the type of a node for use with decorator type metadata.
15601563 *
15611564 * @param node The node that should have its type serialized.
15621565 */
1563- function serializeTypeOfNode ( node : Node ) : Expression {
1566+ function serializeTypeOfNode ( node : Node ) : SerializedTypeNode {
15641567 switch ( node . kind ) {
15651568 case SyntaxKind . PropertyDeclaration :
15661569 case SyntaxKind . Parameter :
@@ -1582,15 +1585,15 @@ namespace ts {
15821585 *
15831586 * @param node The node that should have its parameter types serialized.
15841587 */
1585- function serializeParameterTypesOfNode ( node : Node , container : ClassLikeDeclaration ) : Expression {
1588+ function serializeParameterTypesOfNode ( node : Node , container : ClassLikeDeclaration ) : ArrayLiteralExpression {
15861589 const valueDeclaration =
15871590 isClassLike ( node )
15881591 ? getFirstConstructorWithBody ( node )
15891592 : isFunctionLike ( node ) && nodeIsPresent ( node . body )
15901593 ? node
15911594 : undefined ;
15921595
1593- const expressions : Expression [ ] = [ ] ;
1596+ const expressions : SerializedTypeNode [ ] = [ ] ;
15941597 if ( valueDeclaration ) {
15951598 const parameters = getParametersOfDecoratedDeclaration ( valueDeclaration , container ) ;
15961599 const numParameters = parameters . length ;
@@ -1626,7 +1629,7 @@ namespace ts {
16261629 *
16271630 * @param node The node that should have its return type serialized.
16281631 */
1629- function serializeReturnTypeOfNode ( node : Node ) : Expression {
1632+ function serializeReturnTypeOfNode ( node : Node ) : SerializedTypeNode {
16301633 if ( isFunctionLike ( node ) && node . type ) {
16311634 return serializeTypeNode ( node . type ) ;
16321635 }
@@ -1655,13 +1658,16 @@ namespace ts {
16551658 *
16561659 * @param node The type node to serialize.
16571660 */
1658- function serializeTypeNode ( node : TypeNode ) : Expression {
1661+ function serializeTypeNode ( node : TypeNode ) : SerializedTypeNode {
16591662 if ( node === undefined ) {
16601663 return createIdentifier ( "Object" ) ;
16611664 }
16621665
16631666 switch ( node . kind ) {
16641667 case SyntaxKind . VoidKeyword :
1668+ case SyntaxKind . UndefinedKeyword :
1669+ case SyntaxKind . NullKeyword :
1670+ case SyntaxKind . NeverKeyword :
16651671 return createVoidZero ( ) ;
16661672
16671673 case SyntaxKind . ParenthesizedType :
@@ -1713,37 +1719,8 @@ namespace ts {
17131719
17141720 case SyntaxKind . IntersectionType :
17151721 case SyntaxKind . UnionType :
1716- {
1717- const unionOrIntersection = < UnionOrIntersectionTypeNode > node ;
1718- let serializedUnion : Identifier ;
1719- 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- }
1726-
1727- // One of the individual is global object, return immediately
1728- if ( serializedIndividual . text === "Object" ) {
1729- return serializedIndividual ;
1730- }
1731-
1732- // Different types
1733- if ( serializedUnion && serializedUnion . text !== serializedIndividual . text ) {
1734- serializedUnion = undefined ;
1735- break ;
1736- }
1737-
1738- serializedUnion = serializedIndividual ;
1739- }
1722+ return serializeUnionOrIntersectionType ( < UnionOrIntersectionTypeNode > node ) ;
17401723
1741- // If we were able to find common type
1742- if ( serializedUnion ) {
1743- return serializedUnion ;
1744- }
1745- }
1746- // Fallthrough
17471724 case SyntaxKind . TypeQuery :
17481725 case SyntaxKind . TypeOperator :
17491726 case SyntaxKind . IndexedAccessType :
@@ -1761,13 +1738,48 @@ namespace ts {
17611738 return createIdentifier ( "Object" ) ;
17621739 }
17631740
1741+ function serializeUnionOrIntersectionType ( node : UnionOrIntersectionTypeNode ) : SerializedTypeNode {
1742+ let serializedUnion : SerializedTypeNode ;
1743+ for ( const typeNode of node . types ) {
1744+ const serializedIndividual = serializeTypeNode ( typeNode ) ;
1745+
1746+ if ( isVoidExpression ( serializedIndividual ) ) {
1747+ // If we dont have any other type already set, set the initial type
1748+ if ( ! serializedUnion ) {
1749+ serializedUnion = serializedIndividual ;
1750+ }
1751+ }
1752+ else if ( isIdentifier ( serializedIndividual ) && serializedIndividual . text === "Object" ) {
1753+ // One of the individual is global object, return immediately
1754+ return serializedIndividual ;
1755+ }
1756+ // If there exists union that is not void 0 expression, check if the the common type is identifier.
1757+ // anything more complex and we will just default to Object
1758+ else if ( serializedUnion && ! isVoidExpression ( serializedUnion ) ) {
1759+ // Different types
1760+ if ( ! isIdentifier ( serializedUnion ) ||
1761+ ! isIdentifier ( serializedIndividual ) ||
1762+ serializedUnion . text !== serializedIndividual . text ) {
1763+ return createIdentifier ( "Object" ) ;
1764+ }
1765+ }
1766+ else {
1767+ // Initialize the union type
1768+ serializedUnion = serializedIndividual ;
1769+ }
1770+ }
1771+
1772+ // If we were able to find common type, use it
1773+ return serializedUnion ;
1774+ }
1775+
17641776 /**
17651777 * Serializes a TypeReferenceNode to an appropriate JS constructor value for use with
17661778 * decorator type metadata.
17671779 *
17681780 * @param node The type reference node.
17691781 */
1770- function serializeTypeReferenceNode ( node : TypeReferenceNode ) {
1782+ function serializeTypeReferenceNode ( node : TypeReferenceNode ) : SerializedTypeNode {
17711783 switch ( resolver . getTypeReferenceSerializationKind ( node . typeName , currentScope ) ) {
17721784 case TypeReferenceSerializationKind . Unknown :
17731785 const serialized = serializeEntityNameAsExpression ( node . typeName , /*useFallback*/ true ) ;
@@ -1822,7 +1834,7 @@ namespace ts {
18221834 * @param useFallback A value indicating whether to use logical operators to test for the
18231835 * entity name at runtime.
18241836 */
1825- function serializeEntityNameAsExpression ( node : EntityName , useFallback : boolean ) : Expression {
1837+ function serializeEntityNameAsExpression ( node : EntityName , useFallback : boolean ) : SerializedEntityNameAsExpression {
18261838 switch ( node . kind ) {
18271839 case SyntaxKind . Identifier :
18281840 // Create a clone of the name with a new parent, and treat it as if it were
@@ -1855,8 +1867,8 @@ namespace ts {
18551867 * @param useFallback A value indicating whether to use logical operators to test for the
18561868 * qualified name at runtime.
18571869 */
1858- function serializeQualifiedNameAsExpression ( node : QualifiedName , useFallback : boolean ) : Expression {
1859- let left : Expression ;
1870+ function serializeQualifiedNameAsExpression ( node : QualifiedName , useFallback : boolean ) : PropertyAccessExpression {
1871+ let left : SerializedEntityNameAsExpression ;
18601872 if ( node . left . kind === SyntaxKind . Identifier ) {
18611873 left = serializeEntityNameAsExpression ( node . left , useFallback ) ;
18621874 }
@@ -1881,7 +1893,7 @@ namespace ts {
18811893 * Gets an expression that points to the global "Symbol" constructor at runtime if it is
18821894 * available.
18831895 */
1884- function getGlobalSymbolNameWithFallback ( ) : Expression {
1896+ function getGlobalSymbolNameWithFallback ( ) : ConditionalExpression {
18851897 return createConditional (
18861898 createTypeCheck ( createIdentifier ( "Symbol" ) , "function" ) ,
18871899 createIdentifier ( "Symbol" ) ,
0 commit comments