From 72723e93bebe87c657ebe1c69f771b00b3d4f780 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sat, 7 Nov 2015 16:56:16 -0800 Subject: [PATCH] do not report 'excess property error' if object literal pattern contains computed properties --- src/compiler/checker.ts | 15 ++++++-- src/compiler/types.ts | 1 + ...putedPropertiesInDestructuring1.errors.txt | 38 +------------------ ...dPropertiesInDestructuring1_ES6.errors.txt | 38 +------------------ 4 files changed, 15 insertions(+), 77 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb15d6d9401..8b3b0417d5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2500,10 +2500,12 @@ namespace ts { // Return the type implied by an object binding pattern function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type { const members: SymbolTable = {}; + let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; if (isComputedNonLiteralName(name)) { // do not include computed properties in the implied type + hasComputedProperties = true; return; } @@ -2518,6 +2520,9 @@ namespace ts { if (includePatternInType) { result.pattern = pattern; } + if (hasComputedProperties) { + result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties; + } return result; } @@ -5010,7 +5015,7 @@ namespace ts { } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { + if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -7428,6 +7433,7 @@ namespace ts { (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); let typeFlags: TypeFlags = 0; + let patternWithComputedProperties = false; for (const memberDecl of node.properties) { let member = memberDecl.symbol; if (memberDecl.kind === SyntaxKind.PropertyAssignment || @@ -7455,8 +7461,11 @@ namespace ts { if (isOptional) { prop.flags |= SymbolFlags.Optional; } + if (hasDynamicName(memberDecl)) { + patternWithComputedProperties = true; + } } - else if (contextualTypeHasPattern) { + else if (contextualTypeHasPattern && !(contextualType.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties)) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.name); @@ -7513,7 +7522,7 @@ namespace ts { const numberIndexType = getIndexType(IndexKind.Number); const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral; - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); if (inDestructuringPattern) { result.pattern = node; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index af6200ac023..4ed64b07f17 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1822,6 +1822,7 @@ namespace ts { ContainsAnyFunctionType = 0x00800000, // Type is or contains object literal type ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6 ThisType = 0x02000000, // This type + ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties /* @internal */ Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt b/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt index 682db92f95f..dc536e544b2 100644 --- a/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt +++ b/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt @@ -1,41 +1,21 @@ -tests/cases/compiler/computedPropertiesInDestructuring1.ts(3,21): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(8,25): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(10,25): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(11,28): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,8): error TS2349: Cannot invoke an expression whose type lacks a call signature. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,27): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1.ts(21,12): error TS2339: Property 'toExponential' does not exist on type 'string'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(21,41): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(24,18): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(28,22): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(30,21): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(31,24): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,4): error TS2349: Cannot invoke an expression whose type lacks a call signature. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,23): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,5): error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,26): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -==== tests/cases/compiler/computedPropertiesInDestructuring1.ts (16 errors) ==== +==== tests/cases/compiler/computedPropertiesInDestructuring1.ts (4 errors) ==== // destructuring in variable declarations let foo = "bar"; let {[foo]: bar} = {bar: "bar"}; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let {["bar"]: bar2} = {bar: "bar"}; let foo2 = () => "bar"; let {[foo2()]: bar3} = {bar: "bar"}; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo]: bar4}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo2()]: bar5}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. function f1({["bar"]: x}: { bar: number }) {} function f2({[foo]: x}: { bar: number }) {} @@ -47,42 +27,26 @@ tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,26): error TS2353: let [{[foo()]: bar6}] = [{bar: "bar"}]; ~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; ~~~~~~~~~~~~~ !!! error TS2339: Property 'toExponential' does not exist on type 'string'. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. // destructuring assignment ({[foo]: bar} = {bar: "bar"}); - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. ({["bar"]: bar2} = {bar: "bar"}); ({[foo2()]: bar3} = {bar: "bar"}); - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo]: bar4}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo2()]: bar5}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo()]: bar4}] = [{bar: "bar"}]; ~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[(1 + {})]: bar4}] = [{bar: "bar"}]; ~~~~~~ !!! error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt index 1866cf1d543..96ab892d1b9 100644 --- a/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt @@ -1,42 +1,22 @@ -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(3,21): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(9,25): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(11,25): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(12,28): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(21,8): error TS2349: Cannot invoke an expression whose type lacks a call signature. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(21,27): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(22,12): error TS2339: Property 'toExponential' does not exist on type 'string'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(22,41): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(25,18): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(29,22): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(31,21): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(32,24): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(34,4): error TS2349: Cannot invoke an expression whose type lacks a call signature. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(34,23): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(35,5): error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. -tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(35,26): error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. -==== tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts (16 errors) ==== +==== tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts (4 errors) ==== // destructuring in variable declarations let foo = "bar"; let {[foo]: bar} = {bar: "bar"}; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let {["bar"]: bar2} = {bar: "bar"}; let {[11]: bar2_1} = {11: "bar"}; let foo2 = () => "bar"; let {[foo2()]: bar3} = {bar: "bar"}; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo]: bar4}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo2()]: bar5}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. function f1({["bar"]: x}: { bar: number }) {} function f2({[foo]: x}: { bar: number }) {} @@ -48,40 +28,24 @@ tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(35,26): error TS2 let [{[foo()]: bar6}] = [{bar: "bar"}]; ~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; ~~~~~~~~~~~~~ !!! error TS2339: Property 'toExponential' does not exist on type 'string'. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. // destructuring assignment ({[foo]: bar} = {bar: "bar"}); - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. ({["bar"]: bar2} = {bar: "bar"}); ({[foo2()]: bar3} = {bar: "bar"}); - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo]: bar4}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo2()]: bar5}] = [{bar: "bar"}]; - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[foo()]: bar4}] = [{bar: "bar"}]; ~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. [{[(1 + {})]: bar4}] = [{bar: "bar"}]; ~~~~~~ !!! error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. - ~~~ -!!! error TS2353: Object literal may only specify known properties, and 'bar' does not exist in type '{}'. \ No newline at end of file