diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f279dea186a7a..708b6eaa696f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5621,7 +5621,7 @@ module ts { } var isConstEnum = isConstEnumObjectType(objectType); - if (isConstEnum && + if (isConstEnum && (!node.argumentExpression || node.argumentExpression.kind !== SyntaxKind.StringLiteral)) { error(node.argumentExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); return unknownType; @@ -5653,10 +5653,10 @@ module ts { } // Check for compatible indexer types. - if (indexType.flags & (TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike) || isTypeAssignableTo(indexType, stringOrNumberType)) { + if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike)) { // Try to use a number indexer. - if (indexType.flags & (TypeFlags.Any | TypeFlags.NumberLike) || isTypeAssignableTo(indexType, numberType)) { + if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.NumberLike)) { var numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number); if (numberIndexType) { return numberIndexType; @@ -6557,7 +6557,7 @@ module ts { } function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean { - if (!(type.flags & (TypeFlags.Any | TypeFlags.NumberLike))) { + if (!isTypeOfKind(type, TypeFlags.Any | TypeFlags.NumberLike)) { error(operand, diagnostic); return false; } @@ -6708,12 +6708,21 @@ module ts { return numberType; } - // Return true if type an object type, a type parameter, or a union type composed of only those kinds of types - function isStructuredType(type: Type): boolean { + // Return true if type has the given flags, or is a union type composed of types that all have those flags + function isTypeOfKind(type: Type, kind: TypeFlags): boolean { + if (type.flags & kind) { + return true; + } if (type.flags & TypeFlags.Union) { - return !forEach((type).types, t => !isStructuredType(t)); + var types = (type).types; + for (var i = 0; i < types.length; i++) { + if (!(types[i].flags & kind)) { + return false; + } + } + return true; } - return (type.flags & (TypeFlags.ObjectType | TypeFlags.TypeParameter)) !== 0; + return false; } function isConstEnumObjectType(type: Type): boolean { @@ -6730,7 +6739,7 @@ module ts { // and the right operand to be of type Any or a subtype of the 'Function' interface type. // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported - if (!(leftType.flags & TypeFlags.Any || isStructuredType(leftType))) { + if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } // NOTE: do not raise error if right is unknown as related error was already reported @@ -6745,10 +6754,10 @@ module ts { // The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type, // and the right operand to be of type Any, an object type, or a type parameter type. // The result is always of the Boolean primitive type. - if (leftType !== anyType && leftType !== stringType && leftType !== numberType) { + if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike)) { error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number); } - if (!(rightType.flags & TypeFlags.Any || isStructuredType(rightType))) { + if (!isTypeOfKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; @@ -6909,16 +6918,16 @@ module ts { if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType; var resultType: Type; - if (leftType.flags & TypeFlags.NumberLike && rightType.flags & TypeFlags.NumberLike) { + if (isTypeOfKind(leftType, TypeFlags.NumberLike) && isTypeOfKind(rightType, TypeFlags.NumberLike)) { // Operands of an enum type are treated as having the primitive type Number. // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; } - else if (leftType.flags & TypeFlags.StringLike || rightType.flags & TypeFlags.StringLike) { + else if (isTypeOfKind(leftType, TypeFlags.StringLike) || isTypeOfKind(rightType, TypeFlags.StringLike)) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; } - else if (leftType.flags & TypeFlags.Any || leftType === unknownType || rightType.flags & TypeFlags.Any || rightType === unknownType) { + else if (leftType.flags & TypeFlags.Any || rightType.flags & TypeFlags.Any) { // Otherwise, the result is of type Any. // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. resultType = anyType; @@ -8274,7 +8283,7 @@ module ts { var exprType = checkExpression(node.expression); // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (!(exprType.flags & TypeFlags.Any || isStructuredType(exprType))) { + if (!isTypeOfKind(exprType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); }