From 35bbfdca80a34feb89c05f1bb0f77a7d66bdb53a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 3 Mar 2020 11:29:52 -0800 Subject: [PATCH 1/2] More precise property-overwritten-by-spread errors Trying to do this check in getSpreadType just doesn't have enough information, so I moved it to checkObjectLiteral, which is a better place for issuing errors anyway. Unfortunately, the approach is kind of expensive in that it 1. creates a new map for each property and 2. iterates over all properties of the spread type, even if it's a union. I have some ideas to improve (1) that might work out. I'm not sure how bad (2) is since we're going to iterate over all properties of all constituents of a union. Fixes #36779 --- src/compiler/checker.ts | 34 ++++++------- .../objectSpreadSetonlyAccessor.errors.txt | 9 ++++ .../spreadOverwritesPropertyStrict.errors.txt | 9 ++++ .../spreadOverwritesPropertyStrict.js | 18 +++++++ .../spreadOverwritesPropertyStrict.symbols | 32 ++++++++++++ .../spreadOverwritesPropertyStrict.types | 49 +++++++++++++++++++ .../spread/spreadOverwritesPropertyStrict.ts | 9 ++++ 7 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18d32322297f0..2c5c8d41389b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13154,7 +13154,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean, isParentTypeNullable?: boolean): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -13170,16 +13170,16 @@ namespace ts { if (left.flags & TypeFlags.Union) { const merged = tryMergeUnionOfObjectTypeAndEmptyObject(left as UnionType, readonly); if (merged) { - return getSpreadType(merged, right, symbol, objectFlags, readonly, isParentTypeNullable); + return getSpreadType(merged, right, symbol, objectFlags, readonly); } - return mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly, isParentTypeNullable)); + return mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly)); } if (right.flags & TypeFlags.Union) { const merged = tryMergeUnionOfObjectTypeAndEmptyObject(right as UnionType, readonly); if (merged) { - return getSpreadType(left, merged, symbol, objectFlags, readonly, maybeTypeOfKind(right, TypeFlags.Nullable)); + return getSpreadType(left, merged, symbol, objectFlags, readonly); } - return mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly, maybeTypeOfKind(right, TypeFlags.Nullable))); + return mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { return left; @@ -13243,14 +13243,6 @@ namespace ts { result.nameType = getSymbolLinks(leftProp).nameType; members.set(leftProp.escapedName, result); } - else if (strictNullChecks && - !isParentTypeNullable && - symbol && - !isFromSpreadAssignment(leftProp, symbol) && - isFromSpreadAssignment(rightProp, symbol) && - !maybeTypeOfKind(rightType, TypeFlags.Nullable)) { - error(leftProp.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(leftProp.escapedName)); - } } else { members.set(leftProp.escapedName, getSpreadSymbol(leftProp, readonly)); @@ -16781,10 +16773,6 @@ namespace ts { return match === -1 || discriminable.indexOf(/*searchElement*/ true, match + 1) !== -1 ? defaultValue : target.types[match]; } - function isFromSpreadAssignment(prop: Symbol, container: Symbol) { - return prop.valueDeclaration?.parent !== container.valueDeclaration; - } - /** * A type is 'weak' if it is an object type with at least one optional property * and no required properties, call/construct signatures or index signatures @@ -22560,6 +22548,7 @@ namespace ts { let patternWithComputedProperties = false; let hasComputedStringProperty = false; let hasComputedNumberProperty = false; + const propertyDeclarations = createMap(); propertiesTable = createSymbolTable(); let offset = 0; @@ -22626,6 +22615,7 @@ namespace ts { prop.type = type; prop.target = member; member = prop; + propertyDeclarations.set(prop.escapedName as string, prop); } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (languageVersion < ScriptTarget.ES2015) { @@ -22643,6 +22633,16 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return errorType; } + for (const right of getPropertiesOfType(type)) { + const rightType = getTypeOfSymbol(right); + const left = propertyDeclarations.get(right.escapedName as string); + if (strictNullChecks && + left && + !maybeTypeOfKind(rightType, TypeFlags.Nullable)) { + error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); + } + } + spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext); offset = i + 1; continue; diff --git a/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt b/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt new file mode 100644 index 0000000000000..cb3eb23d9722e --- /dev/null +++ b/tests/baselines/reference/objectSpreadSetonlyAccessor.errors.txt @@ -0,0 +1,9 @@ +tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts(2,34): error TS2783: 'foo' is specified more than once, so this usage will be overwritten. + + +==== tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts (1 errors) ==== + const o1: { foo: number, bar: undefined } = { foo: 1, ... { set bar(_v: number) { } } } + const o2: { foo: undefined } = { foo: 1, ... { set foo(_v: number) { } } } + ~~~~~~ +!!! error TS2783: 'foo' is specified more than once, so this usage will be overwritten. + \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt index 4abf968184b6f..dab2a97e4295e 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt @@ -23,4 +23,13 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(15,14): e ~~~~ !!! error TS2783: 'x' is specified more than once, so this usage will be overwritten. } + function i(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...(b ? t : {}) } // ok + } + function j() { + return { ...{ command: "hi" } , ...{ command: "bye" } } // ok + } + function k(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok + } \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.js b/tests/baselines/reference/spreadOverwritesPropertyStrict.js index 001f134098404..f4c0bdf794ade 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.js +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.js @@ -15,6 +15,15 @@ function f(obj: { x: number } | undefined) { function h(obj: { x: number } | { x: string }) { return { x: 1, ...obj } // error } +function i(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...(b ? t : {}) } // ok +} +function j() { + return { ...{ command: "hi" } , ...{ command: "bye" } } // ok +} +function k(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +} //// [spreadOverwritesPropertyStrict.js] @@ -44,3 +53,12 @@ function f(obj) { function h(obj) { return __assign({ x: 1 }, obj); // error } +function i(b, t) { + return __assign({ command: "hi" }, (b ? t : {})); // ok +} +function j() { + return __assign({ command: "hi" }, { command: "bye" }); // ok +} +function k(b, t) { + return __assign(__assign({ command: "hi" }, { spoiler: true }), (b ? t : {})); // ok +} diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols index 02e1e4037519d..cd17d1f223be0 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols @@ -62,4 +62,36 @@ function h(obj: { x: number } | { x: string }) { >x : Symbol(x, Decl(spreadOverwritesPropertyStrict.ts, 14, 12)) >obj : Symbol(obj, Decl(spreadOverwritesPropertyStrict.ts, 13, 11)) } +function i(b: boolean, t: { command: string, ok: string }) { +>i : Symbol(i, Decl(spreadOverwritesPropertyStrict.ts, 15, 1)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 16, 11)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 16, 22)) +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 16, 27)) +>ok : Symbol(ok, Decl(spreadOverwritesPropertyStrict.ts, 16, 44)) + + return { command: "hi", ...(b ? t : {}) } // ok +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 17, 12)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 16, 11)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 16, 22)) +} +function j() { +>j : Symbol(j, Decl(spreadOverwritesPropertyStrict.ts, 18, 1)) + + return { ...{ command: "hi" } , ...{ command: "bye" } } // ok +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 20, 17)) +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 20, 40)) +} +function k(b: boolean, t: { command: string, ok: string }) { +>k : Symbol(k, Decl(spreadOverwritesPropertyStrict.ts, 21, 1)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 22)) +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 22, 27)) +>ok : Symbol(ok, Decl(spreadOverwritesPropertyStrict.ts, 22, 44)) + + return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 23, 12)) +>spoiler : Symbol(spoiler, Decl(spreadOverwritesPropertyStrict.ts, 23, 32)) +>b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 22)) +} diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.types b/tests/baselines/reference/spreadOverwritesPropertyStrict.types index 55c142da247f5..fb11fce412041 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.types +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.types @@ -77,4 +77,53 @@ function h(obj: { x: number } | { x: string }) { >1 : 1 >obj : { x: number; } | { x: string; } } +function i(b: boolean, t: { command: string, ok: string }) { +>i : (b: boolean, t: { command: string; ok: string; }) => { command: string; ok: string; } | { command: string; } +>b : boolean +>t : { command: string; ok: string; } +>command : string +>ok : string + + return { command: "hi", ...(b ? t : {}) } // ok +>{ command: "hi", ...(b ? t : {}) } : { command: string; ok: string; } | { command: string; } +>command : string +>"hi" : "hi" +>(b ? t : {}) : { command: string; ok: string; } | {} +>b ? t : {} : { command: string; ok: string; } | {} +>b : boolean +>t : { command: string; ok: string; } +>{} : {} +} +function j() { +>j : () => { command: string; } + + return { ...{ command: "hi" } , ...{ command: "bye" } } // ok +>{ ...{ command: "hi" } , ...{ command: "bye" } } : { command: string; } +>{ command: "hi" } : { command: string; } +>command : string +>"hi" : "hi" +>{ command: "bye" } : { command: string; } +>command : string +>"bye" : "bye" +} +function k(b: boolean, t: { command: string, ok: string }) { +>k : (b: boolean, t: { command: string; ok: string; }) => { command: string; ok: string; spoiler: boolean; } | { spoiler: boolean; command: string; } +>b : boolean +>t : { command: string; ok: string; } +>command : string +>ok : string + + return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +>{ command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } : { command: string; ok: string; spoiler: boolean; } | { spoiler: boolean; command: string; } +>command : string +>"hi" : "hi" +>{ spoiler: true } : { spoiler: boolean; } +>spoiler : boolean +>true : true +>(b ? t : {}) : { command: string; ok: string; } | {} +>b ? t : {} : { command: string; ok: string; } | {} +>b : boolean +>t : { command: string; ok: string; } +>{} : {} +} diff --git a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts index 65d53dcd77533..1367eea1ca662 100644 --- a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts +++ b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts @@ -15,3 +15,12 @@ function f(obj: { x: number } | undefined) { function h(obj: { x: number } | { x: string }) { return { x: 1, ...obj } // error } +function i(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...(b ? t : {}) } // ok +} +function j() { + return { ...{ command: "hi" } , ...{ command: "bye" } } // ok +} +function k(b: boolean, t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +} From d350638d206ece354ad75be281f9160131cb2b26 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 3 Mar 2020 14:48:57 -0800 Subject: [PATCH 2/2] another test and rename --- src/compiler/checker.ts | 6 +++--- .../spreadOverwritesPropertyStrict.errors.txt | 9 ++++++--- .../reference/spreadOverwritesPropertyStrict.js | 8 ++++---- .../spreadOverwritesPropertyStrict.symbols | 15 +++++++-------- .../spreadOverwritesPropertyStrict.types | 15 ++++++--------- .../spread/spreadOverwritesPropertyStrict.ts | 4 ++-- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2c5c8d41389b6..49c201408feca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22533,6 +22533,7 @@ namespace ts { checkGrammarObjectLiteralExpression(node, inDestructuringPattern); let propertiesTable: SymbolTable; + const allPropertiesTable = createSymbolTable(); let propertiesArray: Symbol[] = []; let spread: Type = emptyObjectType; @@ -22548,7 +22549,6 @@ namespace ts { let patternWithComputedProperties = false; let hasComputedStringProperty = false; let hasComputedNumberProperty = false; - const propertyDeclarations = createMap(); propertiesTable = createSymbolTable(); let offset = 0; @@ -22615,7 +22615,7 @@ namespace ts { prop.type = type; prop.target = member; member = prop; - propertyDeclarations.set(prop.escapedName as string, prop); + allPropertiesTable.set(prop.escapedName, prop); } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (languageVersion < ScriptTarget.ES2015) { @@ -22635,7 +22635,7 @@ namespace ts { } for (const right of getPropertiesOfType(type)) { const rightType = getTypeOfSymbol(right); - const left = propertyDeclarations.get(right.escapedName as string); + const left = allPropertiesTable.get(right.escapedName); if (strictNullChecks && left && !maybeTypeOfKind(rightType, TypeFlags.Nullable)) { diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt index dab2a97e4295e..be9054dfc5146 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt @@ -1,8 +1,9 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(3,17): error TS2783: 'b' is specified more than once, so this usage will be overwritten. tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(15,14): error TS2783: 'x' is specified more than once, so this usage will be overwritten. +tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): error TS2783: 'command' is specified more than once, so this usage will be overwritten. -==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (2 errors) ==== +==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (3 errors) ==== declare var ab: { a: number, b: number }; declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } // error @@ -29,7 +30,9 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(15,14): e function j() { return { ...{ command: "hi" } , ...{ command: "bye" } } // ok } - function k(b: boolean, t: { command: string, ok: string }) { - return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok + function k(t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error + ~~~~~~~~~~~~~ +!!! error TS2783: 'command' is specified more than once, so this usage will be overwritten. } \ No newline at end of file diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.js b/tests/baselines/reference/spreadOverwritesPropertyStrict.js index f4c0bdf794ade..6ca70a1963fa0 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.js +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.js @@ -21,8 +21,8 @@ function i(b: boolean, t: { command: string, ok: string }) { function j() { return { ...{ command: "hi" } , ...{ command: "bye" } } // ok } -function k(b: boolean, t: { command: string, ok: string }) { - return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +function k(t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error } @@ -59,6 +59,6 @@ function i(b, t) { function j() { return __assign({ command: "hi" }, { command: "bye" }); // ok } -function k(b, t) { - return __assign(__assign({ command: "hi" }, { spoiler: true }), (b ? t : {})); // ok +function k(t) { + return __assign(__assign(__assign({ command: "hi" }, { spoiler: true }), { spoiler2: true }), t); // error } diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols index cd17d1f223be0..f9ff36c6598bd 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.symbols @@ -81,17 +81,16 @@ function j() { >command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 20, 17)) >command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 20, 40)) } -function k(b: boolean, t: { command: string, ok: string }) { +function k(t: { command: string, ok: string }) { >k : Symbol(k, Decl(spreadOverwritesPropertyStrict.ts, 21, 1)) ->b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) ->t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 22)) ->command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 22, 27)) ->ok : Symbol(ok, Decl(spreadOverwritesPropertyStrict.ts, 22, 44)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) +>command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 22, 15)) +>ok : Symbol(ok, Decl(spreadOverwritesPropertyStrict.ts, 22, 32)) - return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok + return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error >command : Symbol(command, Decl(spreadOverwritesPropertyStrict.ts, 23, 12)) >spoiler : Symbol(spoiler, Decl(spreadOverwritesPropertyStrict.ts, 23, 32)) ->b : Symbol(b, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) ->t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 22)) +>spoiler2 : Symbol(spoiler2, Decl(spreadOverwritesPropertyStrict.ts, 23, 49)) +>t : Symbol(t, Decl(spreadOverwritesPropertyStrict.ts, 22, 11)) } diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.types b/tests/baselines/reference/spreadOverwritesPropertyStrict.types index fb11fce412041..b063e28d7e5f5 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.types +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.types @@ -106,24 +106,21 @@ function j() { >command : string >"bye" : "bye" } -function k(b: boolean, t: { command: string, ok: string }) { ->k : (b: boolean, t: { command: string; ok: string; }) => { command: string; ok: string; spoiler: boolean; } | { spoiler: boolean; command: string; } ->b : boolean +function k(t: { command: string, ok: string }) { +>k : (t: { command: string; ok: string; }) => { command: string; ok: string; spoiler2: boolean; spoiler: boolean; } >t : { command: string; ok: string; } >command : string >ok : string - return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok ->{ command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } : { command: string; ok: string; spoiler: boolean; } | { spoiler: boolean; command: string; } + return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error +>{ command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } : { command: string; ok: string; spoiler2: boolean; spoiler: boolean; } >command : string >"hi" : "hi" >{ spoiler: true } : { spoiler: boolean; } >spoiler : boolean >true : true ->(b ? t : {}) : { command: string; ok: string; } | {} ->b ? t : {} : { command: string; ok: string; } | {} ->b : boolean +>spoiler2 : boolean +>true : true >t : { command: string; ok: string; } ->{} : {} } diff --git a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts index 1367eea1ca662..2f90accf42142 100644 --- a/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts +++ b/tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts @@ -21,6 +21,6 @@ function i(b: boolean, t: { command: string, ok: string }) { function j() { return { ...{ command: "hi" } , ...{ command: "bye" } } // ok } -function k(b: boolean, t: { command: string, ok: string }) { - return { command: "hi", ...{ spoiler: true }, ...(b ? t : {}) } // ok +function k(t: { command: string, ok: string }) { + return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error }