@@ -1157,7 +1157,7 @@ module ts {
1157
1157
}
1158
1158
}
1159
1159
1160
- function writeTypeList ( types : Type [ ] , union ? : boolean ) {
1160
+ function writeTypeList ( types : Type [ ] , union : boolean ) {
1161
1161
for ( var i = 0 ; i < types . length ; i ++ ) {
1162
1162
if ( i > 0 ) {
1163
1163
if ( union ) {
@@ -1166,6 +1166,8 @@ module ts {
1166
1166
writePunctuation ( writer , union ? SyntaxKind . BarToken : SyntaxKind . CommaToken ) ;
1167
1167
writeSpace ( writer ) ;
1168
1168
}
1169
+ // Don't output function type literals in unions because '() => string | () => number' would be parsed
1170
+ // as a function type that returns a union type. Instead output '{ (): string; } | { (): number; }'.
1169
1171
writeType ( types [ i ] , /*allowFunctionOrConstructorTypeLiteral*/ ! union ) ;
1170
1172
}
1171
1173
}
@@ -1181,14 +1183,14 @@ module ts {
1181
1183
else {
1182
1184
writeSymbol ( type . target . symbol , writer , enclosingDeclaration , SymbolFlags . Type ) ;
1183
1185
writePunctuation ( writer , SyntaxKind . LessThanToken ) ;
1184
- writeTypeList ( type . typeArguments ) ;
1186
+ writeTypeList ( type . typeArguments , /*union*/ false ) ;
1185
1187
writePunctuation ( writer , SyntaxKind . GreaterThanToken ) ;
1186
1188
}
1187
1189
}
1188
1190
1189
1191
function writeTupleType ( type : TupleType ) {
1190
1192
writePunctuation ( writer , SyntaxKind . OpenBracketToken ) ;
1191
- writeTypeList ( type . elementTypes ) ;
1193
+ writeTypeList ( type . elementTypes , /*union*/ false ) ;
1192
1194
writePunctuation ( writer , SyntaxKind . CloseBracketToken ) ;
1193
1195
}
1194
1196
@@ -1744,7 +1746,7 @@ module ts {
1744
1746
function getTypeOfUnionProperty ( symbol : Symbol ) : Type {
1745
1747
var links = getSymbolLinks ( symbol ) ;
1746
1748
if ( ! links . type ) {
1747
- var types = map ( links . unionType . types , t => getTypeOfSymbol ( getPropertyOfType ( getApparentType ( t ) , symbol . name ) || undefinedSymbol ) ) ;
1749
+ var types = map ( links . unionType . types , t => getTypeOfSymbol ( getPropertyOfType ( getApparentType ( t ) , symbol . name ) ) ) ;
1748
1750
links . type = getUnionType ( types ) ;
1749
1751
}
1750
1752
return links . type ;
@@ -2069,25 +2071,37 @@ module ts {
2069
2071
}
2070
2072
2071
2073
function signatureListsIdentical ( s : Signature [ ] , t : Signature [ ] ) : boolean {
2072
- if ( s . length !== t . length ) return false ;
2074
+ if ( s . length !== t . length ) {
2075
+ return false ;
2076
+ }
2073
2077
for ( var i = 0 ; i < s . length ; i ++ ) {
2074
- if ( ! compareSignatures ( s [ i ] , t [ i ] , false , isTypeIdenticalTo ) ) return false ;
2078
+ if ( ! compareSignatures ( s [ i ] , t [ i ] , /*compareReturnTypes*/ false , isTypeIdenticalTo ) ) {
2079
+ return false ;
2080
+ }
2075
2081
}
2076
2082
return true ;
2077
2083
}
2078
2084
2085
+ // If the lists of call or construct signatures in the given types are all identical except for return types,
2086
+ // and if none of the signatures are generic, return a list of signatures that has substitutes a union of the
2087
+ // return types of the corresponding signatures in each resulting signature.
2079
2088
function getUnionSignatures ( types : Type [ ] , kind : SignatureKind ) : Signature [ ] {
2080
2089
var signatureLists = map ( types , t => getSignaturesOfType ( t , kind ) ) ;
2081
- var baseSignatures = signatureLists [ 0 ] ;
2082
- for ( var i = 0 ; i < baseSignatures . length ; i ++ ) {
2083
- if ( baseSignatures [ i ] . typeParameters ) return emptyArray ;
2090
+ var signatures = signatureLists [ 0 ] ;
2091
+ for ( var i = 0 ; i < signatures . length ; i ++ ) {
2092
+ if ( signatures [ i ] . typeParameters ) {
2093
+ return emptyArray ;
2094
+ }
2084
2095
}
2085
2096
for ( var i = 1 ; i < signatureLists . length ; i ++ ) {
2086
- if ( ! signatureListsIdentical ( baseSignatures , signatureLists [ i ] ) ) return emptyArray ;
2097
+ if ( ! signatureListsIdentical ( signatures , signatureLists [ i ] ) ) {
2098
+ return emptyArray ;
2099
+ }
2087
2100
}
2088
- var result = map ( baseSignatures , cloneSignature ) ;
2101
+ var result = map ( signatures , cloneSignature ) ;
2089
2102
for ( var i = 0 ; i < result . length ; i ++ ) {
2090
2103
var s = result [ i ] ;
2104
+ // Clear resolved return type we possibly got from cloneSignature
2091
2105
s . resolvedReturnType = undefined ;
2092
2106
s . unionSignatures = map ( signatureLists , signatures => signatures [ i ] ) ;
2093
2107
}
@@ -2098,7 +2112,9 @@ module ts {
2098
2112
var indexTypes : Type [ ] = [ ] ;
2099
2113
for ( var i = 0 ; i < types . length ; i ++ ) {
2100
2114
var indexType = getIndexTypeOfType ( types [ i ] , kind ) ;
2101
- if ( ! indexType ) return undefined ;
2115
+ if ( ! indexType ) {
2116
+ return undefined ;
2117
+ }
2102
2118
indexTypes . push ( indexType ) ;
2103
2119
}
2104
2120
return getUnionType ( indexTypes ) ;
@@ -2113,14 +2129,16 @@ module ts {
2113
2129
}
2114
2130
} ) ;
2115
2131
if ( types . length <= 1 ) {
2116
- var res = types . length ? resolveObjectTypeMembers ( types [ 0 ] ) : emptyObjectType ;
2117
- setObjectTypeMembers ( type , res . members , res . callSignatures , res . constructSignatures , res . stringIndexType , res . numberIndexType ) ;
2132
+ var resolved = types . length ? resolveObjectTypeMembers ( types [ 0 ] ) : emptyObjectType ;
2133
+ setObjectTypeMembers ( type , resolved . members , resolved . callSignatures , resolved . constructSignatures , resolved . stringIndexType , resolved . numberIndexType ) ;
2118
2134
return ;
2119
2135
}
2120
2136
var members : SymbolTable = { } ;
2121
2137
forEach ( getPropertiesOfType ( types [ 0 ] ) , prop => {
2122
2138
for ( var i = 1 ; i < types . length ; i ++ ) {
2123
- if ( ! getPropertyOfType ( types [ i ] , prop . name ) ) return ;
2139
+ if ( ! getPropertyOfType ( types [ i ] , prop . name ) ) {
2140
+ return ;
2141
+ }
2124
2142
}
2125
2143
var symbol = < TransientSymbol > createSymbol ( SymbolFlags . UnionProperty | SymbolFlags . Transient , prop . name ) ;
2126
2144
symbol . unionType = type ;
@@ -2662,7 +2680,9 @@ module ts {
2662
2680
else {
2663
2681
var i = 0 ;
2664
2682
var id = type . id ;
2665
- while ( i < sortedSet . length && sortedSet [ i ] . id < id ) i ++ ;
2683
+ while ( i < sortedSet . length && sortedSet [ i ] . id < id ) {
2684
+ i ++ ;
2685
+ }
2666
2686
if ( i === sortedSet . length || sortedSet [ i ] . id !== id ) {
2667
2687
sortedSet . splice ( i , 0 , type ) ;
2668
2688
}
@@ -2677,7 +2697,9 @@ module ts {
2677
2697
2678
2698
function isSubtypeOfAny ( candidate : Type , types : Type [ ] ) : boolean {
2679
2699
for ( var i = 0 , len = types . length ; i < len ; i ++ ) {
2680
- if ( candidate !== types [ i ] && isTypeSubtypeOf ( candidate , types [ i ] ) ) return true ;
2700
+ if ( candidate !== types [ i ] && isTypeSubtypeOf ( candidate , types [ i ] ) ) {
2701
+ return true ;
2702
+ }
2681
2703
}
2682
2704
return false ;
2683
2705
}
@@ -3467,7 +3489,7 @@ module ts {
3467
3489
return false ;
3468
3490
}
3469
3491
for ( var i = 0 , len = sourceSignatures . length ; i < len ; ++ i ) {
3470
- if ( ! compareSignatures ( sourceSignatures [ i ] , targetSignatures [ i ] , /*returnTypes */ true , isRelatedTo ) ) {
3492
+ if ( ! compareSignatures ( sourceSignatures [ i ] , targetSignatures [ i ] , /*compareReturnTypes */ true , isRelatedTo ) ) {
3471
3493
return false ;
3472
3494
}
3473
3495
}
@@ -3535,7 +3557,7 @@ module ts {
3535
3557
}
3536
3558
}
3537
3559
3538
- function compareSignatures ( source : Signature , target : Signature , returnTypes : boolean , compareTypes : ( s : Type , t : Type ) => boolean ) : boolean {
3560
+ function compareSignatures ( source : Signature , target : Signature , compareReturnTypes : boolean , compareTypes : ( s : Type , t : Type ) => boolean ) : boolean {
3539
3561
if ( source === target ) {
3540
3562
return true ;
3541
3563
}
@@ -3568,7 +3590,7 @@ module ts {
3568
3590
return false ;
3569
3591
}
3570
3592
}
3571
- return ! returnTypes || compareTypes ( getReturnTypeOfSignature ( source ) , getReturnTypeOfSignature ( target ) ) ;
3593
+ return ! compareReturnTypes || compareTypes ( getReturnTypeOfSignature ( source ) , getReturnTypeOfSignature ( target ) ) ;
3572
3594
}
3573
3595
3574
3596
function isSupertypeOfEach ( candidate : Type , types : Type [ ] ) : boolean {
@@ -3876,20 +3898,14 @@ module ts {
3876
3898
if ( type . flags & TypeFlags . Union ) {
3877
3899
var types = ( < UnionType > type ) . types ;
3878
3900
if ( forEach ( types , t => t . flags & subtractMask ) ) {
3879
- var newTypes : Type [ ] = [ ] ;
3880
- forEach ( types , t => {
3881
- if ( ! ( t . flags & subtractMask ) ) {
3882
- newTypes . push ( t ) ;
3883
- }
3884
- } ) ;
3885
- return getUnionType ( newTypes ) ;
3901
+ return getUnionType ( filter ( types , t => ! ( t . flags & subtractMask ) ) ) ;
3886
3902
}
3887
3903
}
3888
3904
return type ;
3889
3905
}
3890
3906
3891
3907
// Check if a given variable is assigned within a given syntax node
3892
- function IsVariableAssignedWithin ( symbol : Symbol , node : Node ) : boolean {
3908
+ function isVariableAssignedWithin ( symbol : Symbol , node : Node ) : boolean {
3893
3909
var links = getNodeLinks ( node ) ;
3894
3910
if ( links . assignmentChecks ) {
3895
3911
var cachedResult = links . assignmentChecks [ symbol . id ] ;
@@ -3981,29 +3997,32 @@ module ts {
3981
3997
case SyntaxKind . IfStatement :
3982
3998
// In a branch of an if statement, narrow based on controlling expression
3983
3999
if ( child !== ( < IfStatement > node ) . expression ) {
3984
- narrowedType = narrowType ( type , ( < IfStatement > node ) . expression , child === ( < IfStatement > node ) . thenStatement ) ;
4000
+ narrowedType = narrowType ( type , ( < IfStatement > node ) . expression , /*assumeTrue*/ child === ( < IfStatement > node ) . thenStatement ) ;
3985
4001
}
3986
4002
break ;
3987
4003
case SyntaxKind . ConditionalExpression :
3988
4004
// In a branch of a conditional expression, narrow based on controlling condition
3989
4005
if ( child !== ( < ConditionalExpression > node ) . condition ) {
3990
- narrowedType = narrowType ( type , ( < ConditionalExpression > node ) . condition , child === ( < ConditionalExpression > node ) . whenTrue ) ;
4006
+ narrowedType = narrowType ( type , ( < ConditionalExpression > node ) . condition , /*assumeTrue*/ child === ( < ConditionalExpression > node ) . whenTrue ) ;
3991
4007
}
3992
4008
break ;
3993
4009
case SyntaxKind . BinaryExpression :
3994
4010
// In the right operand of an && or ||, narrow based on left operand
3995
4011
if ( child === ( < BinaryExpression > node ) . right ) {
3996
4012
if ( ( < BinaryExpression > node ) . operator === SyntaxKind . AmpersandAmpersandToken ) {
3997
- narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , true ) ;
4013
+ narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , /*assumeTrue*/ true ) ;
3998
4014
}
3999
4015
else if ( ( < BinaryExpression > node ) . operator === SyntaxKind . BarBarToken ) {
4000
- narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , false ) ;
4016
+ narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , /*assumeTrue*/ false ) ;
4001
4017
}
4002
4018
}
4003
4019
break ;
4004
4020
}
4005
4021
// Only use narrowed type if construct contains no assignments to variable
4006
- if ( narrowedType !== type && ! IsVariableAssignedWithin ( symbol , node ) ) {
4022
+ if ( narrowedType !== type ) {
4023
+ if ( isVariableAssignedWithin ( symbol , node ) ) {
4024
+ break ;
4025
+ }
4007
4026
type = narrowedType ;
4008
4027
}
4009
4028
}
@@ -4039,30 +4058,36 @@ module ts {
4039
4058
function narrowTypeByAnd ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
4040
4059
if ( assumeTrue ) {
4041
4060
// The assumed result is true, therefore we narrow assuming each operand to be true.
4042
- return narrowType ( narrowType ( type , expr . left , true ) , expr . right , true ) ;
4061
+ return narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ true ) , expr . right , /*assumeTrue*/ true ) ;
4043
4062
}
4044
4063
else {
4045
- // The assumed result is true . This means either the first operand was false, or the first operand was true
4064
+ // The assumed result is false . This means either the first operand was false, or the first operand was true
4046
4065
// and the second operand was false. We narrow with those assumptions and union the two resulting types.
4047
- return getUnionType ( [ narrowType ( type , expr . left , false ) , narrowType ( narrowType ( type , expr . left , true ) , expr . right , false ) ] ) ;
4066
+ return getUnionType ( [
4067
+ narrowType ( type , expr . left , /*assumeTrue*/ false ) ,
4068
+ narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ true ) , expr . right , /*assumeTrue*/ false )
4069
+ ] ) ;
4048
4070
}
4049
4071
}
4050
4072
4051
4073
function narrowTypeByOr ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
4052
4074
if ( assumeTrue ) {
4053
4075
// The assumed result is true. This means either the first operand was true, or the first operand was false
4054
4076
// and the second operand was true. We narrow with those assumptions and union the two resulting types.
4055
- return getUnionType ( [ narrowType ( type , expr . left , true ) , narrowType ( narrowType ( type , expr . left , false ) , expr . right , true ) ] ) ;
4077
+ return getUnionType ( [
4078
+ narrowType ( type , expr . left , /*assumeTrue*/ true ) ,
4079
+ narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ false ) , expr . right , /*assumeTrue*/ true )
4080
+ ] ) ;
4056
4081
}
4057
4082
else {
4058
4083
// The assumed result is false, therefore we narrow assuming each operand to be false.
4059
- return narrowType ( narrowType ( type , expr . left , false ) , expr . right , false ) ;
4084
+ return narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ false ) , expr . right , /*assumeTrue*/ false ) ;
4060
4085
}
4061
4086
}
4062
4087
4063
4088
function narrowTypeByInstanceof ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
4064
- // Check that we have variable symbol on the left
4065
- if ( expr . left . kind !== SyntaxKind . Identifier || getResolvedSymbol ( < Identifier > expr . left ) !== symbol ) {
4089
+ // Check that assumed result is true and we have variable symbol on the left
4090
+ if ( ! assumeTrue || expr . left . kind !== SyntaxKind . Identifier || getResolvedSymbol ( < Identifier > expr . left ) !== symbol ) {
4066
4091
return type ;
4067
4092
}
4068
4093
// Check that right operand is a function type with a prototype property
@@ -7198,7 +7223,7 @@ module ts {
7198
7223
return checkArrayType ( < ArrayTypeNode > node ) ;
7199
7224
case SyntaxKind . TupleType :
7200
7225
return checkTupleType ( < TupleTypeNode > node ) ;
7201
- case SyntaxKind . TupleType :
7226
+ case SyntaxKind . UnionType :
7202
7227
return checkUnionType ( < UnionTypeNode > node ) ;
7203
7228
case SyntaxKind . FunctionDeclaration :
7204
7229
return checkFunctionDeclaration ( < FunctionDeclaration > node ) ;
0 commit comments