@@ -107,6 +107,21 @@ module ts {
107
107
var diagnostics: Diagnostic[] = [];
108
108
var diagnosticsModified: boolean = false;
109
109
110
+ var primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = {
111
+ "string": {
112
+ type: stringType,
113
+ flags: TypeFlags.StringLike
114
+ },
115
+ "number": {
116
+ type: numberType,
117
+ flags: TypeFlags.NumberLike
118
+ },
119
+ "boolean": {
120
+ type: booleanType,
121
+ flags: TypeFlags.Boolean
122
+ }
123
+ };
124
+
110
125
function addDiagnostic(diagnostic: Diagnostic) {
111
126
diagnostics.push(diagnostic);
112
127
diagnosticsModified = true;
@@ -4454,12 +4469,15 @@ module ts {
4454
4469
Debug.fail("should not get here");
4455
4470
}
4456
4471
4457
- // Remove one or more primitive types from a union type
4458
- function subtractPrimitiveTypes (type: Type, subtractMask : TypeFlags): Type {
4472
+ // For a union type, remove all constituent types for which the given flags have the given state
4473
+ function removeTypesFromUnionType (type: Type, maskFlags : TypeFlags, maskState: boolean ): Type {
4459
4474
if (type.flags & TypeFlags.Union) {
4460
4475
var types = (<UnionType>type).types;
4461
- if (forEach(types, t => t.flags & subtractMask)) {
4462
- return getUnionType(filter(types, t => !(t.flags & subtractMask)));
4476
+ if (forEach(types, t => !(t.flags & maskFlags) !== maskState)) {
4477
+ var reducedType = getUnionType(filter(types, t => !(t.flags & maskFlags) === maskState));
4478
+ if (reducedType !== emptyObjectType) {
4479
+ return reducedType;
4480
+ }
4463
4481
}
4464
4482
}
4465
4483
return type;
@@ -4635,8 +4653,8 @@ module ts {
4635
4653
// Stop at the first containing function or module declaration
4636
4654
break loop;
4637
4655
}
4638
- // Use narrowed type if it is a subtype and construct contains no assignments to variable
4639
- if (narrowedType !== type && isTypeSubtypeOf(narrowedType, type) ) {
4656
+ // Use narrowed type if construct contains no assignments to variable
4657
+ if (narrowedType !== type) {
4640
4658
if (isVariableAssignedWithin(symbol, node)) {
4641
4659
break;
4642
4660
}
@@ -4656,20 +4674,29 @@ module ts {
4656
4674
if (left.expression.kind !== SyntaxKind.Identifier || getResolvedSymbol(<Identifier>left.expression) !== symbol) {
4657
4675
return type;
4658
4676
}
4659
- var t = right.text;
4660
- var checkType: Type = t === "string" ? stringType : t === "number" ? numberType : t === "boolean" ? booleanType : emptyObjectType;
4677
+ var typeInfo = primitiveTypeInfo[right.text];
4661
4678
if (expr.operator === SyntaxKind.ExclamationEqualsEqualsToken) {
4662
4679
assumeTrue = !assumeTrue;
4663
4680
}
4664
4681
if (assumeTrue) {
4665
- // The assumed result is true. If check was for a primitive type, that type is the narrowed type. Otherwise we can
4666
- // remove the primitive types from the narrowed type.
4667
- return checkType === emptyObjectType ? subtractPrimitiveTypes(type, TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean) : checkType;
4682
+ // Assumed result is true. If check was not for a primitive type, remove all primitive types
4683
+ if (!typeInfo) {
4684
+ return removeTypesFromUnionType(type, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean, true);
4685
+ }
4686
+ // Check was for a primitive type, return that primitive type if it is a subtype
4687
+ if (isTypeSubtypeOf(typeInfo.type, type)) {
4688
+ return typeInfo.type;
4689
+ }
4690
+ // Otherwise, remove all types that aren't of the primitive type kind
4691
+ return removeTypesFromUnionType(type, typeInfo.flags, false);
4668
4692
}
4669
4693
else {
4670
- // The assumed result is false. If check was for a primitive type we can remove that type from the narrowed type.
4694
+ // Assumed result is false. If check was for a primitive type, remove that primitive type
4695
+ if (typeInfo) {
4696
+ return removeTypesFromUnionType(type, typeInfo.flags, true);
4697
+ }
4671
4698
// Otherwise we don't have enough information to do anything.
4672
- return checkType === emptyObjectType ? type : subtractPrimitiveTypes(type, checkType.flags) ;
4699
+ return type;
4673
4700
}
4674
4701
}
4675
4702
0 commit comments