From dfa108f4ec5e2074fe3ef0a26471fa52a5581d1e Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Jul 2015 11:17:07 -0700 Subject: [PATCH] Allow tuples to be widened --- src/compiler/checker.ts | 60 +++++++++++++------ .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 8 +++ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da45c08ab44..5209f02847e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5299,7 +5299,7 @@ namespace ts { * Check if a Type was written as a tuple type literal. * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. */ - function isTupleType(type: Type): boolean { + function isTupleType(type: Type): type is TupleType { return (type.flags & TypeFlags.Tuple) && !!(type).elementTypes; } @@ -5341,37 +5341,53 @@ namespace ts { if (isArrayType(type)) { return createArrayType(getWidenedType((type).typeArguments[0])); } + if (isTupleType(type)) { + return createTupleType(map(type.elementTypes, getWidenedType)); + } } return type; } - function reportWideningErrorsInType(type: Type): boolean { + function reportWideningErrorsInType(type: Type, expression: Expression): boolean { + let errorReported = false; if (type.flags & TypeFlags.Union) { - let errorReported = false; - forEach((type).types, t => { - if (reportWideningErrorsInType(t)) { + for (let t of (type).types) { + if (reportWideningErrorsInType(t, expression)) { errorReported = true; } - }); - return errorReported; + } } if (isArrayType(type)) { - return reportWideningErrorsInType((type).typeArguments[0]); + return reportWideningErrorsInType((type).typeArguments[0], expression); + } + if (isTupleType(type)) { + let { elementTypes } = type; + for (let i = 0; i < elementTypes.length; i++) { + let t = elementTypes[i]; + if (t.flags & TypeFlags.ContainsUndefinedOrNull) { + if (reportWideningErrorsInType(t, expression)) { + errorReported = true; + } + else if (expression.kind === SyntaxKind.ArrayLiteralExpression) { + let element = (expression).elements[i]; + error(element, Diagnostics.Array_element_at_index_0_implicitly_has_an_1_type, i, typeToString(getWidenedType(t))); + errorReported = true; + } + } + } } if (type.flags & TypeFlags.ObjectLiteral) { - let errorReported = false; - forEach(getPropertiesOfObjectType(type), p => { + for (let p of getPropertiesOfObjectType(type)) { let t = getTypeOfSymbol(p); if (t.flags & TypeFlags.ContainsUndefinedOrNull) { - if (!reportWideningErrorsInType(t)) { + if (!reportWideningErrorsInType(t, expression)) { error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); } errorReported = true; } - }); - return errorReported; + } } - return false; + return errorReported; } function reportImplicitAnyError(declaration: Declaration, type: Type) { @@ -5409,7 +5425,7 @@ namespace ts { function reportErrorsFromWidening(declaration: Declaration, type: Type) { if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) { // Report implicit any error within type if possible, otherwise report error on declaration - if (!reportWideningErrorsInType(type)) { + if (!reportWideningErrorsInType(type, declaration.kind === SyntaxKind.VariableDeclaration && (declaration).initializer)) { reportImplicitAnyError(declaration, type); } } @@ -6785,6 +6801,7 @@ namespace ts { let hasSpreadElement = false; let elementTypes: Type[] = []; let inDestructuringPattern = isAssignmentTarget(node); + let typeFlags: TypeFlags; for (let e of elements) { if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) { // Given the following situation: @@ -6804,21 +6821,23 @@ namespace ts { (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { elementTypes.push(restElementType); + typeFlags |= restElementType.flags; } } else { let type = checkExpression(e, contextualMapper); elementTypes.push(type); + typeFlags |= type.flags; } hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression; } if (!hasSpreadElement) { let contextualType = getContextualType(node); if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) { - return createTupleType(elementTypes); + return addTypeFlags(createTupleType(elementTypes), typeFlags & TypeFlags.RequiresWidening); } } - return createArrayType(getUnionType(elementTypes)); + return addTypeFlags(createArrayType(getUnionType(elementTypes)), typeFlags & TypeFlags.RequiresWidening); } function isNumericName(name: DeclarationName): boolean { @@ -6934,8 +6953,7 @@ namespace ts { let stringIndexType = getIndexType(IndexKind.String); let numberIndexType = getIndexType(IndexKind.Number); let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull); - return result; + return addTypeFlags(result, TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull)); function getIndexType(kind: IndexKind) { if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { @@ -6961,6 +6979,10 @@ namespace ts { } } + function addTypeFlags(type: Type, flags: TypeFlags): Type { + type.flags |= flags; + return type; + } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index a0a95d47c8c..ce28cbbc387 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -589,6 +589,7 @@ namespace ts { 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." }, 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." }, 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" }, + 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." }, You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." }, 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." }, import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index acf4e74ae9f..65e3bab9ec5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2347,6 +2347,14 @@ "category": "Error", "code": 7026 }, + "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists": { + "category": "Error", + "code": 7026 + }, + "Array element at index {0} implicitly has an '{1}' type.": { + "category": "Error", + "code": 7027 + }, "You cannot rename this element.": {