mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-26 20:14:05 -05:00
* 'in' should not operate on primitive types * accept baselines of failing tests * review * update error message * check if constraint of right type is assignable to a non primitive or instantiable non primitive * do not throw errors where narrowing is impossible * accept baselines * fix test case failures * Add more accurate comment discussion and document failing edge case in test * Update baselines Co-authored-by: Jonas Hübotter <jonas.huebotter@gmail.com>
This commit is contained in:
@@ -30305,14 +30305,36 @@ namespace ts {
|
||||
rightType = checkNonNullType(rightType, right);
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||
// 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.
|
||||
// and the right operand to be
|
||||
//
|
||||
// 1. assignable to the non-primitive type,
|
||||
// 2. an unconstrained type parameter,
|
||||
// 3. a union or intersection including one or more type parameters, whose constituents are all assignable to the
|
||||
// the non-primitive type, or are unconstrainted type parameters, or have constraints assignable to the
|
||||
// non-primitive type, or
|
||||
// 4. a type parameter whose constraint is
|
||||
// i. an object type,
|
||||
// ii. the non-primitive type, or
|
||||
// iii. a union or intersection with at least one constituent assignable to an object or non-primitive type.
|
||||
//
|
||||
// The divergent behavior for type parameters and unions containing type parameters is a workaround for type
|
||||
// parameters not being narrowable. If the right operand is a concrete type, we can error if there is any chance
|
||||
// it is a primitive. But if the operand is a type parameter, it cannot be narrowed, so we don't issue an error
|
||||
// unless *all* instantiations would result in an error.
|
||||
//
|
||||
// The result is always of the Boolean primitive type.
|
||||
if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
|
||||
isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol);
|
||||
}
|
||||
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) {
|
||||
error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
const rightTypeConstraint = getConstraintOfType(rightType);
|
||||
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
|
||||
rightTypeConstraint && (
|
||||
isTypeAssignableToKind(rightType, TypeFlags.UnionOrIntersection) && !allTypesAssignableToKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
|
||||
!maybeTypeOfKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object)
|
||||
)
|
||||
) {
|
||||
error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_not_be_a_primitive);
|
||||
}
|
||||
return booleanType;
|
||||
}
|
||||
|
||||
@@ -1625,7 +1625,7 @@
|
||||
"category": "Error",
|
||||
"code": 2360
|
||||
},
|
||||
"The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.": {
|
||||
"The right-hand side of an 'in' expression must not be a primitive.": {
|
||||
"category": "Error",
|
||||
"code": 2361
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user