@@ -1982,18 +1982,16 @@ namespace ts {
1982
1982
const kind = resolver . getTypeReferenceSerializationKind ( node . typeName , currentNameScope || currentLexicalScope ) ;
1983
1983
switch ( kind ) {
1984
1984
case TypeReferenceSerializationKind . Unknown :
1985
- const serialized = serializeEntityNameAsExpression ( node . typeName , /*useFallback*/ true ) ;
1985
+ const serialized = serializeEntityNameAsExpressionFallback ( node . typeName ) ;
1986
1986
const temp = createTempVariable ( hoistVariableDeclaration ) ;
1987
- return createLogicalOr (
1988
- createLogicalAnd (
1989
- createTypeCheck ( createAssignment ( temp , serialized ) , "function" ) ,
1990
- temp
1991
- ) ,
1987
+ return createConditional (
1988
+ createTypeCheck ( createAssignment ( temp , serialized ) , "function" ) ,
1989
+ temp ,
1992
1990
createIdentifier ( "Object" )
1993
1991
) ;
1994
1992
1995
1993
case TypeReferenceSerializationKind . TypeWithConstructSignatureAndValue :
1996
- return serializeEntityNameAsExpression ( node . typeName , /*useFallback*/ false ) ;
1994
+ return serializeEntityNameAsExpression ( node . typeName ) ;
1997
1995
1998
1996
case TypeReferenceSerializationKind . VoidNullableOrNeverType :
1999
1997
return createVoidZero ( ) ;
@@ -2028,14 +2026,46 @@ namespace ts {
2028
2026
}
2029
2027
}
2030
2028
2029
+ function createCheckedValue ( left : Expression , right : Expression ) {
2030
+ return createLogicalAnd (
2031
+ createStrictInequality ( createTypeOf ( left ) , createLiteral ( "undefined" ) ) ,
2032
+ right
2033
+ ) ;
2034
+ }
2035
+
2036
+ /**
2037
+ * Serializes an entity name which may not exist at runtime, but whose access shouldn't throw
2038
+ *
2039
+ * @param node The entity name to serialize.
2040
+ */
2041
+ function serializeEntityNameAsExpressionFallback ( node : EntityName ) : BinaryExpression {
2042
+ if ( node . kind === SyntaxKind . Identifier ) {
2043
+ // A -> typeof A !== undefined && A
2044
+ const copied = serializeEntityNameAsExpression ( node ) ;
2045
+ return createCheckedValue ( copied , copied ) ;
2046
+ }
2047
+ if ( node . left . kind === SyntaxKind . Identifier ) {
2048
+ // A.B -> typeof A !== undefined && A.B
2049
+ return createCheckedValue ( serializeEntityNameAsExpression ( node . left ) , serializeEntityNameAsExpression ( node ) ) ;
2050
+ }
2051
+ // A.B.C -> typeof A !== undefined && (_a = A.B) !== void 0 && _a.C
2052
+ const left = serializeEntityNameAsExpressionFallback ( node . left ) ;
2053
+ const temp = createTempVariable ( hoistVariableDeclaration ) ;
2054
+ return createLogicalAnd (
2055
+ createLogicalAnd (
2056
+ left . left ,
2057
+ createStrictInequality ( createAssignment ( temp , left . right ) , createVoidZero ( ) )
2058
+ ) ,
2059
+ createPropertyAccess ( temp , node . right )
2060
+ ) ;
2061
+ }
2062
+
2031
2063
/**
2032
2064
* Serializes an entity name as an expression for decorator type metadata.
2033
2065
*
2034
2066
* @param node The entity name to serialize.
2035
- * @param useFallback A value indicating whether to use logical operators to test for the
2036
- * entity name at runtime.
2037
2067
*/
2038
- function serializeEntityNameAsExpression ( node : EntityName , useFallback : boolean ) : SerializedEntityNameAsExpression {
2068
+ function serializeEntityNameAsExpression ( node : EntityName ) : SerializedEntityNameAsExpression {
2039
2069
switch ( node . kind ) {
2040
2070
case SyntaxKind . Identifier :
2041
2071
// Create a clone of the name with a new parent, and treat it as if it were
@@ -2044,20 +2074,11 @@ namespace ts {
2044
2074
name . flags &= ~ NodeFlags . Synthesized ;
2045
2075
name . original = undefined ;
2046
2076
name . parent = getParseTreeNode ( currentLexicalScope ) ; // ensure the parent is set to a parse tree node.
2047
- if ( useFallback ) {
2048
- return createLogicalAnd (
2049
- createStrictInequality (
2050
- createTypeOf ( name ) ,
2051
- createLiteral ( "undefined" )
2052
- ) ,
2053
- name
2054
- ) ;
2055
- }
2056
2077
2057
2078
return name ;
2058
2079
2059
2080
case SyntaxKind . QualifiedName :
2060
- return serializeQualifiedNameAsExpression ( node , useFallback ) ;
2081
+ return serializeQualifiedNameAsExpression ( node ) ;
2061
2082
}
2062
2083
}
2063
2084
@@ -2068,26 +2089,8 @@ namespace ts {
2068
2089
* @param useFallback A value indicating whether to use logical operators to test for the
2069
2090
* qualified name at runtime.
2070
2091
*/
2071
- function serializeQualifiedNameAsExpression ( node : QualifiedName , useFallback : boolean ) : PropertyAccessExpression {
2072
- let left : SerializedEntityNameAsExpression ;
2073
- if ( node . left . kind === SyntaxKind . Identifier ) {
2074
- left = serializeEntityNameAsExpression ( node . left , useFallback ) ;
2075
- }
2076
- else if ( useFallback ) {
2077
- const temp = createTempVariable ( hoistVariableDeclaration ) ;
2078
- left = createLogicalAnd (
2079
- createAssignment (
2080
- temp ,
2081
- serializeEntityNameAsExpression ( node . left , /*useFallback*/ true )
2082
- ) ,
2083
- temp
2084
- ) ;
2085
- }
2086
- else {
2087
- left = serializeEntityNameAsExpression ( node . left , /*useFallback*/ false ) ;
2088
- }
2089
-
2090
- return createPropertyAccess ( left , node . right ) ;
2092
+ function serializeQualifiedNameAsExpression ( node : QualifiedName ) : SerializedEntityNameAsExpression {
2093
+ return createPropertyAccess ( serializeEntityNameAsExpression ( node . left ) , node . right ) ;
2091
2094
}
2092
2095
2093
2096
/**
0 commit comments