From 99f352f295e678a1bc46af54be0fa75683a2c41c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 10:44:00 -0800 Subject: [PATCH] Rest of untyped binding pattern is string-indexed type This is more correct than any and the code is more elegant as well. --- src/compiler/checker.ts | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65bc52fde1f..c4920c29770 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3099,15 +3099,6 @@ namespace ts { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } - const parent = pattern.parent as VariableLikeDeclaration; - if (parent.kind === SyntaxKind.Parameter && - !parent.type && - !parent.initializer && - !getContextuallyTypedParameterType(parent as ParameterDeclaration)) { - // if this type came from examining the structure of the pattern -- - // there was no other information -- then it is not sufficient to determine the rest type, so just return any - return anyType; - } const literalMembers: PropertyName[] = []; for (const element of pattern.elements) { if (!(element as BindingElement).dotDotDotToken) { @@ -3318,14 +3309,19 @@ namespace ts { // Return the type implied by an object binding pattern function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const members = createMap(); + let stringIndexInfo: IndexInfo; let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; - if (isComputedNonLiteralName(name) || e.dotDotDotToken) { - // do not include computed properties or rests in the implied type + if (isComputedNonLiteralName(name)) { + // do not include computed properties in the implied type hasComputedProperties = true; return; } + if (e.dotDotDotToken) { + stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); + return; + } const text = getTextOfPropertyName(name); const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); @@ -3334,7 +3330,7 @@ namespace ts { symbol.bindingElement = e; members[symbol.name] = symbol; }); - const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + const result = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, undefined); if (includePatternInType) { result.pattern = pattern; } @@ -11422,7 +11418,8 @@ namespace ts { if (impliedProp) { prop.flags |= impliedProp.flags & SymbolFlags.Optional; } - else if (!compilerOptions.suppressExcessPropertyErrors) { + + else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, IndexKind.String)) { error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(member), typeToString(contextualType)); }