Skip to content

Commit dfa108f

Browse files
committed
Allow tuples to be widened
1 parent 649e40b commit dfa108f

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

src/compiler/checker.ts

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5299,7 +5299,7 @@ namespace ts {
52995299
* Check if a Type was written as a tuple type literal.
53005300
* Prefer using isTupleLikeType() unless the use of `elementTypes` is required.
53015301
*/
5302-
function isTupleType(type: Type): boolean {
5302+
function isTupleType(type: Type): type is TupleType {
53035303
return (type.flags & TypeFlags.Tuple) && !!(<TupleType>type).elementTypes;
53045304
}
53055305

@@ -5341,37 +5341,53 @@ namespace ts {
53415341
if (isArrayType(type)) {
53425342
return createArrayType(getWidenedType((<TypeReference>type).typeArguments[0]));
53435343
}
5344+
if (isTupleType(type)) {
5345+
return createTupleType(map(type.elementTypes, getWidenedType));
5346+
}
53445347
}
53455348
return type;
53465349
}
53475350

5348-
function reportWideningErrorsInType(type: Type): boolean {
5351+
function reportWideningErrorsInType(type: Type, expression: Expression): boolean {
5352+
let errorReported = false;
53495353
if (type.flags & TypeFlags.Union) {
5350-
let errorReported = false;
5351-
forEach((<UnionType>type).types, t => {
5352-
if (reportWideningErrorsInType(t)) {
5354+
for (let t of (<UnionType>type).types) {
5355+
if (reportWideningErrorsInType(t, expression)) {
53535356
errorReported = true;
53545357
}
5355-
});
5356-
return errorReported;
5358+
}
53575359
}
53585360
if (isArrayType(type)) {
5359-
return reportWideningErrorsInType((<TypeReference>type).typeArguments[0]);
5361+
return reportWideningErrorsInType((<TypeReference>type).typeArguments[0], expression);
5362+
}
5363+
if (isTupleType(type)) {
5364+
let { elementTypes } = type;
5365+
for (let i = 0; i < elementTypes.length; i++) {
5366+
let t = elementTypes[i];
5367+
if (t.flags & TypeFlags.ContainsUndefinedOrNull) {
5368+
if (reportWideningErrorsInType(t, expression)) {
5369+
errorReported = true;
5370+
}
5371+
else if (expression.kind === SyntaxKind.ArrayLiteralExpression) {
5372+
let element = (<ArrayLiteralExpression>expression).elements[i];
5373+
error(element, Diagnostics.Array_element_at_index_0_implicitly_has_an_1_type, i, typeToString(getWidenedType(t)));
5374+
errorReported = true;
5375+
}
5376+
}
5377+
}
53605378
}
53615379
if (type.flags & TypeFlags.ObjectLiteral) {
5362-
let errorReported = false;
5363-
forEach(getPropertiesOfObjectType(type), p => {
5380+
for (let p of getPropertiesOfObjectType(type)) {
53645381
let t = getTypeOfSymbol(p);
53655382
if (t.flags & TypeFlags.ContainsUndefinedOrNull) {
5366-
if (!reportWideningErrorsInType(t)) {
5383+
if (!reportWideningErrorsInType(t, expression)) {
53675384
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t)));
53685385
}
53695386
errorReported = true;
53705387
}
5371-
});
5372-
return errorReported;
5388+
}
53735389
}
5374-
return false;
5390+
return errorReported;
53755391
}
53765392

53775393
function reportImplicitAnyError(declaration: Declaration, type: Type) {
@@ -5409,7 +5425,7 @@ namespace ts {
54095425
function reportErrorsFromWidening(declaration: Declaration, type: Type) {
54105426
if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) {
54115427
// Report implicit any error within type if possible, otherwise report error on declaration
5412-
if (!reportWideningErrorsInType(type)) {
5428+
if (!reportWideningErrorsInType(type, declaration.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>declaration).initializer)) {
54135429
reportImplicitAnyError(declaration, type);
54145430
}
54155431
}
@@ -6785,6 +6801,7 @@ namespace ts {
67856801
let hasSpreadElement = false;
67866802
let elementTypes: Type[] = [];
67876803
let inDestructuringPattern = isAssignmentTarget(node);
6804+
let typeFlags: TypeFlags;
67886805
for (let e of elements) {
67896806
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) {
67906807
// Given the following situation:
@@ -6804,21 +6821,23 @@ namespace ts {
68046821
(languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined);
68056822
if (restElementType) {
68066823
elementTypes.push(restElementType);
6824+
typeFlags |= restElementType.flags;
68076825
}
68086826
}
68096827
else {
68106828
let type = checkExpression(e, contextualMapper);
68116829
elementTypes.push(type);
6830+
typeFlags |= type.flags;
68126831
}
68136832
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression;
68146833
}
68156834
if (!hasSpreadElement) {
68166835
let contextualType = getContextualType(node);
68176836
if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) {
6818-
return createTupleType(elementTypes);
6837+
return addTypeFlags(createTupleType(elementTypes), typeFlags & TypeFlags.RequiresWidening);
68196838
}
68206839
}
6821-
return createArrayType(getUnionType(elementTypes));
6840+
return addTypeFlags(createArrayType(getUnionType(elementTypes)), typeFlags & TypeFlags.RequiresWidening);
68226841
}
68236842

68246843
function isNumericName(name: DeclarationName): boolean {
@@ -6934,8 +6953,7 @@ namespace ts {
69346953
let stringIndexType = getIndexType(IndexKind.String);
69356954
let numberIndexType = getIndexType(IndexKind.Number);
69366955
let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType);
6937-
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull);
6938-
return result;
6956+
return addTypeFlags(result, TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull));
69396957

69406958
function getIndexType(kind: IndexKind) {
69416959
if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) {
@@ -6961,6 +6979,10 @@ namespace ts {
69616979
}
69626980
}
69636981

6982+
function addTypeFlags(type: Type, flags: TypeFlags): Type {
6983+
type.flags |= flags;
6984+
return type;
6985+
}
69646986

69656987
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
69666988
checkJsxOpeningLikeElement(node);

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ namespace ts {
589589
Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
590590
Generator_implicitly_has_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type: { code: 7025, category: DiagnosticCategory.Error, key: "Generator implicitly has type '{0}' because it does not yield any values. Consider supplying a return type." },
591591
JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists: { code: 7026, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists" },
592+
Array_element_at_index_0_implicitly_has_an_1_type: { code: 7027, category: DiagnosticCategory.Error, key: "Array element at index {0} implicitly has an '{1}' type." },
592593
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
593594
You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." },
594595
import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." },

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,14 @@
23472347
"category": "Error",
23482348
"code": 7026
23492349
},
2350+
"JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists": {
2351+
"category": "Error",
2352+
"code": 7026
2353+
},
2354+
"Array element at index {0} implicitly has an '{1}' type.": {
2355+
"category": "Error",
2356+
"code": 7027
2357+
},
23502358

23512359

23522360
"You cannot rename this element.": {

0 commit comments

Comments
 (0)