diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 91234ebb38..e4d6929fe6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2434,6 +2434,7 @@ namespace ts { let name = e.propertyName || e.name; let symbol = createSymbol(flags, name.text); symbol.type = getTypeFromBindingElement(e, includePatternInType); + symbol.bindingElement = e; members[symbol.name] = symbol; }); let result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); @@ -2451,12 +2452,12 @@ namespace ts { } // If the pattern has at least one element, and no rest element, then it should imply a tuple type. let elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType)); - let result = createTupleType(elementTypes); if (includePatternInType) { - result = clone(result); + let result = createNewTupleType(elementTypes); result.pattern = pattern; + return result; } - return result; + return createTupleType(elementTypes); } // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself @@ -3124,7 +3125,7 @@ namespace ts { } function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature { - for (let s of signatureList) { + for (let s of signatureList) { if (compareSignatures(s, signature, partialMatch, ignoreReturnTypes, compareTypes)) { return s; } @@ -4045,11 +4046,12 @@ namespace ts { function createTupleType(elementTypes: Type[]) { let id = getTypeListId(elementTypes); - let type = tupleTypes[id]; - if (!type) { - type = tupleTypes[id] = createObjectType(TypeFlags.Tuple | getPropagatingFlagsOfTypes(elementTypes)); - type.elementTypes = elementTypes; - } + return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes)); + } + + function createNewTupleType(elementTypes: Type[]) { + let type = createObjectType(TypeFlags.Tuple | getPropagatingFlagsOfTypes(elementTypes)); + type.elementTypes = elementTypes; return type; } @@ -7042,19 +7044,28 @@ namespace ts { // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such // that we get the same behavior for "var [x, y] = []" and "[x, y] = []". if (inDestructuringPattern && elementTypes.length) { - let type = clone(createTupleType(elementTypes)); + let type = createNewTupleType(elementTypes); type.pattern = node; return type; } let contextualType = getContextualType(node); if (contextualType && contextualTypeIsTupleLikeType(contextualType)) { let pattern = contextualType.pattern; - // If array literal is contextually typed by a binding pattern or an assignment pattern, pad the - // resulting tuple type to make the lengths equal. + // If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting + // tuple type with the corresponding binding or assignment element types to make the lengths equal. if (pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) { let patternElements = (pattern).elements; for (let i = elementTypes.length; i < patternElements.length; i++) { - elementTypes.push(hasDefaultValue(patternElements[i]) ? (contextualType).elementTypes[i] : undefinedType); + let patternElement = patternElements[i]; + if (hasDefaultValue(patternElement)) { + elementTypes.push((contextualType).elementTypes[i]); + } + else { + if (patternElement.kind !== SyntaxKind.OmittedExpression) { + error(patternElement, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); + } + elementTypes.push(unknownType); + } } } if (elementTypes.length) { @@ -7201,7 +7212,11 @@ namespace ts { // type with those properties for which the binding pattern specifies a default value. if (contextualTypeHasPattern) { for (let prop of getPropertiesOfType(contextualType)) { - if (prop.flags & SymbolFlags.Optional && !hasProperty(propertiesTable, prop.name)) { + if (!hasProperty(propertiesTable, prop.name)) { + if (!(prop.flags & SymbolFlags.Optional)) { + error(prop.valueDeclaration || (prop).bindingElement, + Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); + } propertiesTable[prop.name] = prop; propertiesArray.push(prop); } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index f7351bf691..9686d6580f 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -415,6 +415,7 @@ namespace ts { The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." }, yield_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2523, category: DiagnosticCategory.Error, key: "'yield' expressions cannot be used in a parameter initializer." }, await_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2524, category: DiagnosticCategory.Error, key: "'await' expressions cannot be used in a parameter initializer." }, + Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value: { code: 2525, category: DiagnosticCategory.Error, key: "Initializer provides no value for this binding element and the binding element has no default value" }, JSX_element_attributes_type_0_must_be_an_object_type: { code: 2600, category: DiagnosticCategory.Error, key: "JSX element attributes type '{0}' must be an object type." }, The_return_type_of_a_JSX_element_constructor_must_return_an_object_type: { code: 2601, category: DiagnosticCategory.Error, key: "The return type of a JSX element constructor must return an object type." }, JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist: { code: 2602, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9fd08ef9bc..515afda49a 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1649,6 +1649,10 @@ "category": "Error", "code": 2524 }, + "Initializer provides no value for this binding element and the binding element has no default value": { + "category": "Error", + "code": 2525 + }, "JSX element attributes type '{0}' must be an object type.": { "category": "Error", "code": 2600 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d23a42e753..cfdf869dd7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1714,6 +1714,7 @@ namespace ts { resolvedExports?: SymbolTable; // Resolved exports of module exportsChecked?: boolean; // True if exports of external module have been checked isNestedRedeclaration?: boolean; // True if symbol is block scoped redeclaration + bindingElement?: BindingElement; // Binding element associated with property symbol } /* @internal */