mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Address PR feedback
This commit is contained in:
parent
22f80b9582
commit
6691408147
@ -4763,17 +4763,22 @@ module ts {
|
||||
|
||||
// For a union type, remove all constituent types that are of the given type kind (when isOfTypeKind is true)
|
||||
// or not of the given type kind (when isOfTypeKind is false)
|
||||
function removeTypesFromUnionType(type: Type, typeKind: TypeFlags, isOfTypeKind: boolean): Type {
|
||||
function removeTypesFromUnionType(type: Type, typeKind: TypeFlags, isOfTypeKind: boolean, allowEmptyUnionResult: boolean): Type {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
var types = (<UnionType>type).types;
|
||||
if (forEach(types, t => !!(t.flags & typeKind) === isOfTypeKind)) {
|
||||
// Above we checked if we have anything to remove, now use the opposite test to do the removal
|
||||
var narrowedType = getUnionType(filter(types, t => !(t.flags & typeKind) === isOfTypeKind));
|
||||
if (narrowedType !== emptyObjectType) {
|
||||
if (allowEmptyUnionResult || narrowedType !== emptyObjectType) {
|
||||
return narrowedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (allowEmptyUnionResult && !!(type.flags & typeKind) === isOfTypeKind) {
|
||||
// Use getUnionType(emptyArray) instead of emptyObjectType in case the way empty union types
|
||||
// are represented ever changes.
|
||||
return getUnionType(emptyArray);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -4976,7 +4981,8 @@ module ts {
|
||||
if (assumeTrue) {
|
||||
// Assumed result is true. If check was not for a primitive type, remove all primitive types
|
||||
if (!typeInfo) {
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean | TypeFlags.ESSymbol, /*isOfTypeKind*/ true);
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean | TypeFlags.ESSymbol,
|
||||
/*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false);
|
||||
}
|
||||
// Check was for a primitive type, return that primitive type if it is a subtype
|
||||
if (isTypeSubtypeOf(typeInfo.type, type)) {
|
||||
@ -4984,12 +4990,12 @@ module ts {
|
||||
}
|
||||
// Otherwise, remove all types that aren't of the primitive type kind. This can happen when the type is
|
||||
// union of enum types and other types.
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ false);
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ false, /*allowEmptyUnionResult*/ false);
|
||||
}
|
||||
else {
|
||||
// Assumed result is false. If check was for a primitive type, remove that primitive type
|
||||
if (typeInfo) {
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ true);
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false);
|
||||
}
|
||||
// Otherwise we don't have enough information to do anything.
|
||||
return type;
|
||||
@ -9027,28 +9033,55 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function does the following steps:
|
||||
* 1. Break up arrayOrStringType (possibly a union) into its string constituents and array constituents.
|
||||
* 2. Take the element types of the array constituents.
|
||||
* 3. Return the union of the element types, and string if there was a string constitutent.
|
||||
*
|
||||
* For example:
|
||||
* string -> string
|
||||
* number[] -> number
|
||||
* string[] | number[] -> string | number
|
||||
* string | number[] -> string | number
|
||||
* string | string[] | number[] -> string | number
|
||||
*
|
||||
* It also errors if:
|
||||
* 1. Some constituent is neither a string nor an array.
|
||||
* 2. Some constituent is a string and target is less than ES5 (because in ES3 string is not indexable).
|
||||
*/
|
||||
function checkElementTypeOfArrayOrString(arrayOrStringType: Type, expressionForError: Expression): Type {
|
||||
Debug.assert(languageVersion < ScriptTarget.ES6);
|
||||
var isJustString = allConstituentTypesHaveKind(arrayOrStringType, TypeFlags.StringLike);
|
||||
|
||||
// Check isJustString because removeTypesFromUnionType will only remove types if it doesn't result
|
||||
// in an emptyObjectType. In this case, we actually do want the emptyObjectType.
|
||||
var arrayType = isJustString ? emptyObjectType : removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true);
|
||||
var hasStringConstituent = arrayOrStringType !== emptyObjectType && arrayOrStringType !== arrayType;
|
||||
// After we remove all types that are StringLike, we will know if there was a string constituent
|
||||
// based on whether the remaining type is the same as the initial type.
|
||||
var arrayType = removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true, /*allowEmptyUnionResult*/ true);
|
||||
var hasStringConstituent = arrayOrStringType !== arrayType;
|
||||
|
||||
var reportedError = false;
|
||||
if (hasStringConstituent && languageVersion < ScriptTarget.ES5) {
|
||||
error(expressionForError, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher);
|
||||
reportedError = true;
|
||||
}
|
||||
if (hasStringConstituent) {
|
||||
if (languageVersion < ScriptTarget.ES5) {
|
||||
error(expressionForError, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher);
|
||||
reportedError = true;
|
||||
}
|
||||
|
||||
if (isJustString) {
|
||||
return stringType;
|
||||
// Now that we've removed all the StringLike types, if no constituents remain, then the entire
|
||||
// arrayOrStringType was a string.
|
||||
if (arrayType === emptyObjectType) {
|
||||
return stringType;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isArrayLikeType(arrayType)) {
|
||||
if (!reportedError) {
|
||||
error(expressionForError, Diagnostics.Type_0_is_not_an_array_type, typeToString(arrayType));
|
||||
// Which error we report depends on whether there was a string constituent. For example,
|
||||
// if the input type is number | string, we want to say that number is not an array type.
|
||||
// But if the input was just number, we want to say that number is not an array type
|
||||
// or a string type.
|
||||
var diagnostic = hasStringConstituent
|
||||
? Diagnostics.Type_0_is_not_an_array_type
|
||||
: Diagnostics.Type_0_is_not_an_array_type_or_a_string_type;
|
||||
error(expressionForError, diagnostic, typeToString(arrayType));
|
||||
}
|
||||
return hasStringConstituent ? stringType : unknownType;
|
||||
}
|
||||
|
||||
@ -339,6 +339,7 @@ module ts {
|
||||
Cannot_redeclare_identifier_0_in_catch_clause: { code: 2492, category: DiagnosticCategory.Error, key: "Cannot redeclare identifier '{0}' in catch clause" },
|
||||
Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2: { code: 2493, category: DiagnosticCategory.Error, key: "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'." },
|
||||
Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher: { code: 2494, category: DiagnosticCategory.Error, key: "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher." },
|
||||
Type_0_is_not_an_array_type_or_a_string_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type or a string type." },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
|
||||
|
||||
@ -1347,6 +1347,10 @@
|
||||
"category": "Error",
|
||||
"code": 2494
|
||||
},
|
||||
"Type '{0}' is not an array type or a string type.": {
|
||||
"category": "Error",
|
||||
"code": 2461
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(1,15): error TS2461: Type 'StringIterator' is not an array type.
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(1,15): error TS2461: Type 'StringIterator' is not an array type or a string type.
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(11,6): error TS2304: Cannot find name 'Symbol'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts (2 errors) ====
|
||||
for (var v of new StringIterator) { }
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2461: Type 'StringIterator' is not an array type.
|
||||
!!! error TS2461: Type 'StringIterator' is not an array type or a string type.
|
||||
|
||||
// In ES3/5, you cannot for...of over an arbitrary iterable.
|
||||
class StringIterator {
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck12.ts(1,17): error TS2461: Type 'number' is not an array type or a string type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck12.ts (1 errors) ====
|
||||
for (const v of 0) { }
|
||||
~
|
||||
!!! error TS2461: Type 'number' is not an array type or a string type.
|
||||
7
tests/baselines/reference/ES5For-ofTypeCheck12.js
Normal file
7
tests/baselines/reference/ES5For-ofTypeCheck12.js
Normal file
@ -0,0 +1,7 @@
|
||||
//// [ES5For-ofTypeCheck12.ts]
|
||||
for (const v of 0) { }
|
||||
|
||||
//// [ES5For-ofTypeCheck12.js]
|
||||
for (var _i = 0, _a = 0; _i < _a.length; _i++) {
|
||||
var v = _a[_i];
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
//@target: ES5
|
||||
for (const v of 0) { }
|
||||
Loading…
x
Reference in New Issue
Block a user