@@ -4196,13 +4196,20 @@ module ts {
4196
4196
return type ;
4197
4197
}
4198
4198
4199
- function keepAssignableTypes ( type : Type , targetType : Type , assumeAssignable : boolean ) : Type {
4199
+ function keepAssignablePropertyTypes ( type : Type , propertyName : string , targetPropertyType : Type , assumeAssignable : boolean ) : Type {
4200
4200
if ( type . flags & TypeFlags . Union ) {
4201
4201
var types = ( < UnionType > type ) . types ;
4202
4202
} else {
4203
4203
var types = [ type ] ;
4204
4204
}
4205
- var remainingTypes = filter ( types , t => assumeAssignable ? isTypeAssignableTo ( t , targetType ) : ! isTypeAssignableTo ( t , targetType ) ) ;
4205
+ var remainingTypes = filter ( types , t => {
4206
+ var propertyType = getTypeOfPropertyOfContextualType ( t , propertyName ) ;
4207
+ if ( propertyType ) {
4208
+ return assumeAssignable ? isTypeAssignableTo ( targetPropertyType , propertyType ) : ! isTypeAssignableTo ( propertyType , targetPropertyType ) ;
4209
+ } else {
4210
+ return ! assumeAssignable ;
4211
+ }
4212
+ } ) ;
4206
4213
if ( remainingTypes . length > 0 ) {
4207
4214
return getUnionType ( remainingTypes ) ;
4208
4215
}
@@ -4322,6 +4329,11 @@ module ts {
4322
4329
}
4323
4330
}
4324
4331
break ;
4332
+ case SyntaxKind . SwitchStatement :
4333
+ if ( child !== ( < SwitchStatement > node ) . expression ) {
4334
+ narrowedType = narrowTypeInCaseClause ( type , < SwitchStatement > node , < CaseOrDefaultClause > child ) ;
4335
+ }
4336
+ break ;
4325
4337
}
4326
4338
// Only use narrowed type if construct contains no assignments to variable
4327
4339
if ( narrowedType !== type ) {
@@ -4360,9 +4372,7 @@ module ts {
4360
4372
}
4361
4373
}
4362
4374
4363
- function narrowPropTypeByStringTypeEquality ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
4364
- var left = < PropertyAccess > expr . left ;
4365
- var right = expr . right ;
4375
+ function narrowPropTypeByStringTypeEquality ( type : Type , left : PropertyAccess , right : Expression , assumeTrue : boolean ) : Type {
4366
4376
var right_t = checkExpression ( right ) ;
4367
4377
if ( left . kind !== SyntaxKind . PropertyAccess || left . left . kind !== SyntaxKind . Identifier ||
4368
4378
! ( right_t . flags & TypeFlags . StringLiteral ) ||
@@ -4374,12 +4384,49 @@ module ts {
4374
4384
if ( isTypeAssignableTo ( right_t , t ) ) {
4375
4385
smallerType = right_t ;
4376
4386
}
4377
- var dummyProperties : SymbolTable = { } ;
4378
- var dummyProperty = < TransientSymbol > createSymbol ( SymbolFlags . Property | SymbolFlags . Transient , left . right . text ) ;
4379
- dummyProperty . type = smallerType ;
4380
- dummyProperties [ dummyProperty . name ] = dummyProperty ;
4381
- var dummyType = createAnonymousType ( undefined , dummyProperties , emptyArray , emptyArray , undefined , undefined ) ;
4382
- return keepAssignableTypes ( type , dummyType , assumeTrue ) ;
4387
+ var propertyName = left . right . text ;
4388
+ return keepAssignablePropertyTypes ( type , propertyName , smallerType , assumeTrue ) ;
4389
+ }
4390
+
4391
+ function narrowTypeInCaseClause ( type : Type , switchNode : SwitchStatement , caseClause : CaseOrDefaultClause ) : Type {
4392
+ var propertyAccess = < PropertyAccess > switchNode . expression ;
4393
+ if ( switchNode . expression . kind !== SyntaxKind . PropertyAccess ||
4394
+ getResolvedSymbol ( < Identifier > propertyAccess . left ) !== symbol ) {
4395
+ console . log ( "return from alien switch for " + symbol . name ) ;
4396
+ return type ;
4397
+ }
4398
+ var narrowedType = type ;
4399
+ var remainingType = type ;
4400
+ var typesBeforeBreak : Type [ ] = [ ] ;
4401
+ for ( var i = 0 ; i < switchNode . clauses . length ; i ++ ) {
4402
+ var clause = switchNode . clauses [ i ] ;
4403
+ if ( clause . expression ) {
4404
+ narrowedType = narrowPropTypeByStringTypeEquality ( remainingType , < PropertyAccess > switchNode . expression , clause . expression , /* assumeTrue */ true ) ;
4405
+ typesBeforeBreak . push ( narrowedType ) ;
4406
+ narrowedType = getUnionType ( typesBeforeBreak ) ;
4407
+ remainingType = narrowPropTypeByStringTypeEquality ( remainingType , < PropertyAccess > switchNode . expression , clause . expression , /* assumeTrue */ false ) ;
4408
+
4409
+ } else {
4410
+ narrowedType = remainingType ;
4411
+ }
4412
+ console . log ( "clause id : " + clause . id + " while waiting for " + caseClause . id ) ;
4413
+ if ( clause . id === caseClause . id ) {
4414
+ console . log ( "returning in clause : " + typeToString ( narrowedType ) ) ;
4415
+ return narrowedType ;
4416
+ }
4417
+ if ( clause . statements && clause . statements . length > 0 ) {
4418
+ var statements = clause . statements ;
4419
+ var last = statements [ statements . length - 1 ] ;
4420
+ if ( last . kind === SyntaxKind . ReturnStatement ||
4421
+ last . kind === SyntaxKind . BreakStatement ) {
4422
+ typesBeforeBreak = [ ] ;
4423
+ }
4424
+ }
4425
+ }
4426
+
4427
+ console . log ( "attained default clause" ) ;
4428
+
4429
+ return narrowedType ;
4383
4430
}
4384
4431
4385
4432
function narrowTypeByAnd ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
@@ -4440,7 +4487,8 @@ module ts {
4440
4487
var operator = ( < BinaryExpression > expr ) . operator ;
4441
4488
if ( operator === SyntaxKind . EqualsEqualsEqualsToken || operator === SyntaxKind . ExclamationEqualsEqualsToken ) {
4442
4489
if ( ( < BinaryExpression > expr ) . left . kind === SyntaxKind . PropertyAccess ) {
4443
- return narrowPropTypeByStringTypeEquality ( type , < BinaryExpression > expr , assumeTrue ) ;
4490
+ var binary_expr = < BinaryExpression > expr ;
4491
+ return narrowPropTypeByStringTypeEquality ( type , < PropertyAccess > binary_expr . left , binary_expr . right , assumeTrue ) ;
4444
4492
} else {
4445
4493
return narrowTypeByEquality ( type , < BinaryExpression > expr , assumeTrue ) ;
4446
4494
}
0 commit comments