From 3fdb8f102f6c850ffe2c3161fb646f0341055d38 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Jun 2021 07:50:45 -0700 Subject: [PATCH 1/4] Fix check for overwritten properties in object spreads --- src/compiler/checker.ts | 45 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 45328df7aaf47..f4bf4b0b72929 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15368,17 +15368,20 @@ namespace ts { return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); } - function tryMergeUnionOfObjectTypeAndEmptyObject(type: UnionType, readonly: boolean): Type | undefined { - if (every(type.types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { - return find(type.types, isEmptyObjectType) || emptyObjectType; + function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { + if (!(type.flags & TypeFlags.Union)) { + return type; + } + if (every((type as UnionType).types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { + return find((type as UnionType).types, isEmptyObjectType) || emptyObjectType; } - const firstType = find(type.types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const firstType = find((type as UnionType).types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); if (!firstType) { - return undefined; + return type; } - const secondType = firstType && find(type.types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); if (secondType) { - return undefined; + return type; } return getAnonymousPartialType(firstType); @@ -15424,20 +15427,14 @@ namespace ts { if (right.flags & TypeFlags.Never) { return left; } + left = tryMergeUnionOfObjectTypeAndEmptyObject(left, readonly); if (left.flags & TypeFlags.Union) { - const merged = tryMergeUnionOfObjectTypeAndEmptyObject(left as UnionType, readonly); - if (merged) { - return getSpreadType(merged, right, symbol, objectFlags, readonly); - } return checkCrossProductUnion([left, right]) ? mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly)) : errorType; } + right = tryMergeUnionOfObjectTypeAndEmptyObject(right, readonly); if (right.flags & TypeFlags.Union) { - const merged = tryMergeUnionOfObjectTypeAndEmptyObject(right as UnionType, readonly); - if (merged) { - return getSpreadType(left, merged, symbol, objectFlags, readonly); - } return checkCrossProductUnion([left, right]) ? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)) : errorType; @@ -15487,7 +15484,7 @@ namespace ts { const declarations = concatenate(leftProp.declarations, rightProp.declarations); const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.escapedName); - result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]); + result.type = getUnionType([getTypeOfSymbol(leftProp), removeMissingOrUndefinedType(rightType)]); result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; @@ -26305,14 +26302,15 @@ namespace ts { } const type = getReducedType(checkExpression(memberDecl.expression)); if (isValidSpreadType(type)) { + const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject(type, inConstContext); if (allPropertiesTable) { - checkSpreadPropOverrides(type, allPropertiesTable, memberDecl); + checkSpreadPropOverrides(mergedType, allPropertiesTable, memberDecl); } offset = propertiesArray.length; if (spread === errorType) { continue; } - spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext); + spread = getSpreadType(spread, mergedType, node.symbol, objectFlags, inConstContext); } else { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); @@ -26627,11 +26625,12 @@ namespace ts { function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) { for (const right of getPropertiesOfType(type)) { - const left = props.get(right.escapedName); - const rightType = getTypeOfSymbol(right); - if (left && !maybeTypeOfKind(rightType, TypeFlags.Nullable) && !(maybeTypeOfKind(rightType, TypeFlags.AnyOrUnknown) && right.flags & SymbolFlags.Optional)) { - const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); - addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); + if (!(right.flags & SymbolFlags.Optional)) { + const left = props.get(right.escapedName); + if (left) { + const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); + addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); + } } } } From 0aaec179043df332ad3721f307532ca5127ad005 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Jun 2021 07:51:39 -0700 Subject: [PATCH 2/4] Accept new baselines --- .../reference/spreadOverwritesPropertyStrict.errors.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt index 354e7d667a5ee..448e31384e3a5 100644 --- a/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt +++ b/tests/baselines/reference/spreadOverwritesPropertyStrict.errors.txt @@ -1,10 +1,11 @@ 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(9,14): error TS2783: 'x' 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(28,14): error TS2783: 'a' is specified more than once, so this usage will be overwritten. -==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (4 errors) ==== +==== tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts (5 errors) ==== declare var ab: { a: number, b: number }; declare var abq: { a: number, b?: number }; var unused1 = { b: 1, ...ab } // error @@ -17,6 +18,9 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(28,14): e var unused5 = { ...abq, b: 1 } // ok function g(obj: { x: number | undefined }) { return { x: 1, ...obj }; // ok, obj might have x: undefined + ~~~~ +!!! error TS2783: 'x' is specified more than once, so this usage will be overwritten. +!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:9:20: This spread always overwrites this property. } function f(obj: { x: number } | undefined) { return { x: 1, ...obj }; // ok, obj might be undefined From d6ad1990b2efed06a578af440b14f8a603168998 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Jun 2021 07:52:02 -0700 Subject: [PATCH 3/4] Add tests --- .../types/spread/spreadDuplicate.ts | 21 ++++++++++++++++++ .../types/spread/spreadDuplicateExact.ts | 22 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/cases/conformance/types/spread/spreadDuplicate.ts create mode 100644 tests/cases/conformance/types/spread/spreadDuplicateExact.ts diff --git a/tests/cases/conformance/types/spread/spreadDuplicate.ts b/tests/cases/conformance/types/spread/spreadDuplicate.ts new file mode 100644 index 0000000000000..f27a2529f01f5 --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadDuplicate.ts @@ -0,0 +1,21 @@ +// @strict: true +// @declaration: true + +// Repro from #44438 + +declare let a: { a: string }; +declare let b: { a?: string }; +declare let c: { a: string | undefined }; +declare let d: { a?: string | undefined }; + +declare let t: boolean; + +let a1 = { a: 123, ...a }; // string (Error) +let b1 = { a: 123, ...b }; // string | number +let c1 = { a: 123, ...c }; // string | undefined (Error) +let d1 = { a: 123, ...d }; // string | number + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +let c2 = { a: 123, ...(t ? c : {}) }; // string | number +let d2 = { a: 123, ...(t ? d : {}) }; // string | number diff --git a/tests/cases/conformance/types/spread/spreadDuplicateExact.ts b/tests/cases/conformance/types/spread/spreadDuplicateExact.ts new file mode 100644 index 0000000000000..e395af4ce512a --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadDuplicateExact.ts @@ -0,0 +1,22 @@ +// @strict: true +// @exactOptionalPropertyTypes: true +// @declaration: true + +// Repro from #44438 + +declare let a: { a: string }; +declare let b: { a?: string }; +declare let c: { a: string | undefined }; +declare let d: { a?: string | undefined }; + +declare let t: boolean; + +let a1 = { a: 123, ...a }; // string (Error) +let b1 = { a: 123, ...b }; // string | number +let c1 = { a: 123, ...c }; // string | undefined (Error) +let d1 = { a: 123, ...d }; // string | number | undefined + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined +let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined From 8cff8c0cfd91d726986c7f4ef2989476e37ea06d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Jun 2021 07:52:13 -0700 Subject: [PATCH 4/4] Accept new baselines --- .../reference/spreadDuplicate.errors.txt | 30 ++++++ tests/baselines/reference/spreadDuplicate.js | 83 ++++++++++++++++ .../reference/spreadDuplicate.symbols | 66 +++++++++++++ .../baselines/reference/spreadDuplicate.types | 94 +++++++++++++++++++ .../reference/spreadDuplicateExact.errors.txt | 30 ++++++ .../reference/spreadDuplicateExact.js | 83 ++++++++++++++++ .../reference/spreadDuplicateExact.symbols | 66 +++++++++++++ .../reference/spreadDuplicateExact.types | 94 +++++++++++++++++++ 8 files changed, 546 insertions(+) create mode 100644 tests/baselines/reference/spreadDuplicate.errors.txt create mode 100644 tests/baselines/reference/spreadDuplicate.js create mode 100644 tests/baselines/reference/spreadDuplicate.symbols create mode 100644 tests/baselines/reference/spreadDuplicate.types create mode 100644 tests/baselines/reference/spreadDuplicateExact.errors.txt create mode 100644 tests/baselines/reference/spreadDuplicateExact.js create mode 100644 tests/baselines/reference/spreadDuplicateExact.symbols create mode 100644 tests/baselines/reference/spreadDuplicateExact.types diff --git a/tests/baselines/reference/spreadDuplicate.errors.txt b/tests/baselines/reference/spreadDuplicate.errors.txt new file mode 100644 index 0000000000000..f3e7db0159609 --- /dev/null +++ b/tests/baselines/reference/spreadDuplicate.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/types/spread/spreadDuplicate.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten. +tests/cases/conformance/types/spread/spreadDuplicate.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten. + + +==== tests/cases/conformance/types/spread/spreadDuplicate.ts (2 errors) ==== + // Repro from #44438 + + declare let a: { a: string }; + declare let b: { a?: string }; + declare let c: { a: string | undefined }; + declare let d: { a?: string | undefined }; + + declare let t: boolean; + + let a1 = { a: 123, ...a }; // string (Error) + ~~~~~~ +!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten. +!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:10:20: This spread always overwrites this property. + let b1 = { a: 123, ...b }; // string | number + let c1 = { a: 123, ...c }; // string | undefined (Error) + ~~~~~~ +!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten. +!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicate.ts:12:20: This spread always overwrites this property. + let d1 = { a: 123, ...d }; // string | number + + let a2 = { a: 123, ...(t ? a : {}) }; // string | number + let b2 = { a: 123, ...(t ? b : {}) }; // string | number + let c2 = { a: 123, ...(t ? c : {}) }; // string | number + let d2 = { a: 123, ...(t ? d : {}) }; // string | number + \ No newline at end of file diff --git a/tests/baselines/reference/spreadDuplicate.js b/tests/baselines/reference/spreadDuplicate.js new file mode 100644 index 0000000000000..70e659052dcad --- /dev/null +++ b/tests/baselines/reference/spreadDuplicate.js @@ -0,0 +1,83 @@ +//// [spreadDuplicate.ts] +// Repro from #44438 + +declare let a: { a: string }; +declare let b: { a?: string }; +declare let c: { a: string | undefined }; +declare let d: { a?: string | undefined }; + +declare let t: boolean; + +let a1 = { a: 123, ...a }; // string (Error) +let b1 = { a: 123, ...b }; // string | number +let c1 = { a: 123, ...c }; // string | undefined (Error) +let d1 = { a: 123, ...d }; // string | number + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +let c2 = { a: 123, ...(t ? c : {}) }; // string | number +let d2 = { a: 123, ...(t ? d : {}) }; // string | number + + +//// [spreadDuplicate.js] +"use strict"; +// Repro from #44438 +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var a1 = __assign({ a: 123 }, a); // string (Error) +var b1 = __assign({ a: 123 }, b); // string | number +var c1 = __assign({ a: 123 }, c); // string | undefined (Error) +var d1 = __assign({ a: 123 }, d); // string | number +var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number +var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number +var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number +var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number + + +//// [spreadDuplicate.d.ts] +declare let a: { + a: string; +}; +declare let b: { + a?: string; +}; +declare let c: { + a: string | undefined; +}; +declare let d: { + a?: string | undefined; +}; +declare let t: boolean; +declare let a1: { + a: string; +}; +declare let b1: { + a: string | number; +}; +declare let c1: { + a: string | undefined; +}; +declare let d1: { + a: string | number; +}; +declare let a2: { + a: string | number; +}; +declare let b2: { + a: string | number; +}; +declare let c2: { + a: string | number; +}; +declare let d2: { + a: string | number; +}; diff --git a/tests/baselines/reference/spreadDuplicate.symbols b/tests/baselines/reference/spreadDuplicate.symbols new file mode 100644 index 0000000000000..96ce507f772eb --- /dev/null +++ b/tests/baselines/reference/spreadDuplicate.symbols @@ -0,0 +1,66 @@ +=== tests/cases/conformance/types/spread/spreadDuplicate.ts === +// Repro from #44438 + +declare let a: { a: string }; +>a : Symbol(a, Decl(spreadDuplicate.ts, 2, 11)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 2, 16)) + +declare let b: { a?: string }; +>b : Symbol(b, Decl(spreadDuplicate.ts, 3, 11)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 3, 16)) + +declare let c: { a: string | undefined }; +>c : Symbol(c, Decl(spreadDuplicate.ts, 4, 11)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 4, 16)) + +declare let d: { a?: string | undefined }; +>d : Symbol(d, Decl(spreadDuplicate.ts, 5, 11)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 5, 16)) + +declare let t: boolean; +>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11)) + +let a1 = { a: 123, ...a }; // string (Error) +>a1 : Symbol(a1, Decl(spreadDuplicate.ts, 9, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 9, 10)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 2, 11)) + +let b1 = { a: 123, ...b }; // string | number +>b1 : Symbol(b1, Decl(spreadDuplicate.ts, 10, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 10, 10)) +>b : Symbol(b, Decl(spreadDuplicate.ts, 3, 11)) + +let c1 = { a: 123, ...c }; // string | undefined (Error) +>c1 : Symbol(c1, Decl(spreadDuplicate.ts, 11, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 11, 10)) +>c : Symbol(c, Decl(spreadDuplicate.ts, 4, 11)) + +let d1 = { a: 123, ...d }; // string | number +>d1 : Symbol(d1, Decl(spreadDuplicate.ts, 12, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 12, 10)) +>d : Symbol(d, Decl(spreadDuplicate.ts, 5, 11)) + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +>a2 : Symbol(a2, Decl(spreadDuplicate.ts, 14, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 14, 10)) +>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 2, 11)) + +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +>b2 : Symbol(b2, Decl(spreadDuplicate.ts, 15, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 15, 10)) +>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11)) +>b : Symbol(b, Decl(spreadDuplicate.ts, 3, 11)) + +let c2 = { a: 123, ...(t ? c : {}) }; // string | number +>c2 : Symbol(c2, Decl(spreadDuplicate.ts, 16, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 16, 10)) +>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11)) +>c : Symbol(c, Decl(spreadDuplicate.ts, 4, 11)) + +let d2 = { a: 123, ...(t ? d : {}) }; // string | number +>d2 : Symbol(d2, Decl(spreadDuplicate.ts, 17, 3)) +>a : Symbol(a, Decl(spreadDuplicate.ts, 17, 10)) +>t : Symbol(t, Decl(spreadDuplicate.ts, 7, 11)) +>d : Symbol(d, Decl(spreadDuplicate.ts, 5, 11)) + diff --git a/tests/baselines/reference/spreadDuplicate.types b/tests/baselines/reference/spreadDuplicate.types new file mode 100644 index 0000000000000..c9fd44e7bf611 --- /dev/null +++ b/tests/baselines/reference/spreadDuplicate.types @@ -0,0 +1,94 @@ +=== tests/cases/conformance/types/spread/spreadDuplicate.ts === +// Repro from #44438 + +declare let a: { a: string }; +>a : { a: string; } +>a : string + +declare let b: { a?: string }; +>b : { a?: string | undefined; } +>a : string | undefined + +declare let c: { a: string | undefined }; +>c : { a: string | undefined; } +>a : string | undefined + +declare let d: { a?: string | undefined }; +>d : { a?: string | undefined; } +>a : string | undefined + +declare let t: boolean; +>t : boolean + +let a1 = { a: 123, ...a }; // string (Error) +>a1 : { a: string; } +>{ a: 123, ...a } : { a: string; } +>a : number +>123 : 123 +>a : { a: string; } + +let b1 = { a: 123, ...b }; // string | number +>b1 : { a: string | number; } +>{ a: 123, ...b } : { a: string | number; } +>a : number +>123 : 123 +>b : { a?: string | undefined; } + +let c1 = { a: 123, ...c }; // string | undefined (Error) +>c1 : { a: string | undefined; } +>{ a: 123, ...c } : { a: string | undefined; } +>a : number +>123 : 123 +>c : { a: string | undefined; } + +let d1 = { a: 123, ...d }; // string | number +>d1 : { a: string | number; } +>{ a: 123, ...d } : { a: string | number; } +>a : number +>123 : 123 +>d : { a?: string | undefined; } + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +>a2 : { a: string | number; } +>{ a: 123, ...(t ? a : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? a : {}) : { a: string; } | {} +>t ? a : {} : { a: string; } | {} +>t : boolean +>a : { a: string; } +>{} : {} + +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +>b2 : { a: string | number; } +>{ a: 123, ...(t ? b : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? b : {}) : { a?: string | undefined; } +>t ? b : {} : { a?: string | undefined; } +>t : boolean +>b : { a?: string | undefined; } +>{} : {} + +let c2 = { a: 123, ...(t ? c : {}) }; // string | number +>c2 : { a: string | number; } +>{ a: 123, ...(t ? c : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? c : {}) : { a: string | undefined; } | {} +>t ? c : {} : { a: string | undefined; } | {} +>t : boolean +>c : { a: string | undefined; } +>{} : {} + +let d2 = { a: 123, ...(t ? d : {}) }; // string | number +>d2 : { a: string | number; } +>{ a: 123, ...(t ? d : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? d : {}) : { a?: string | undefined; } +>t ? d : {} : { a?: string | undefined; } +>t : boolean +>d : { a?: string | undefined; } +>{} : {} + diff --git a/tests/baselines/reference/spreadDuplicateExact.errors.txt b/tests/baselines/reference/spreadDuplicateExact.errors.txt new file mode 100644 index 0000000000000..5cba7dac81384 --- /dev/null +++ b/tests/baselines/reference/spreadDuplicateExact.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/types/spread/spreadDuplicateExact.ts(10,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten. +tests/cases/conformance/types/spread/spreadDuplicateExact.ts(12,12): error TS2783: 'a' is specified more than once, so this usage will be overwritten. + + +==== tests/cases/conformance/types/spread/spreadDuplicateExact.ts (2 errors) ==== + // Repro from #44438 + + declare let a: { a: string }; + declare let b: { a?: string }; + declare let c: { a: string | undefined }; + declare let d: { a?: string | undefined }; + + declare let t: boolean; + + let a1 = { a: 123, ...a }; // string (Error) + ~~~~~~ +!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten. +!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicateExact.ts:10:20: This spread always overwrites this property. + let b1 = { a: 123, ...b }; // string | number + let c1 = { a: 123, ...c }; // string | undefined (Error) + ~~~~~~ +!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten. +!!! related TS2785 tests/cases/conformance/types/spread/spreadDuplicateExact.ts:12:20: This spread always overwrites this property. + let d1 = { a: 123, ...d }; // string | number | undefined + + let a2 = { a: 123, ...(t ? a : {}) }; // string | number + let b2 = { a: 123, ...(t ? b : {}) }; // string | number + let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined + let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined + \ No newline at end of file diff --git a/tests/baselines/reference/spreadDuplicateExact.js b/tests/baselines/reference/spreadDuplicateExact.js new file mode 100644 index 0000000000000..febbff29f9315 --- /dev/null +++ b/tests/baselines/reference/spreadDuplicateExact.js @@ -0,0 +1,83 @@ +//// [spreadDuplicateExact.ts] +// Repro from #44438 + +declare let a: { a: string }; +declare let b: { a?: string }; +declare let c: { a: string | undefined }; +declare let d: { a?: string | undefined }; + +declare let t: boolean; + +let a1 = { a: 123, ...a }; // string (Error) +let b1 = { a: 123, ...b }; // string | number +let c1 = { a: 123, ...c }; // string | undefined (Error) +let d1 = { a: 123, ...d }; // string | number | undefined + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined +let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined + + +//// [spreadDuplicateExact.js] +"use strict"; +// Repro from #44438 +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var a1 = __assign({ a: 123 }, a); // string (Error) +var b1 = __assign({ a: 123 }, b); // string | number +var c1 = __assign({ a: 123 }, c); // string | undefined (Error) +var d1 = __assign({ a: 123 }, d); // string | number | undefined +var a2 = __assign({ a: 123 }, (t ? a : {})); // string | number +var b2 = __assign({ a: 123 }, (t ? b : {})); // string | number +var c2 = __assign({ a: 123 }, (t ? c : {})); // string | number | undefined +var d2 = __assign({ a: 123 }, (t ? d : {})); // string | number | undefined + + +//// [spreadDuplicateExact.d.ts] +declare let a: { + a: string; +}; +declare let b: { + a?: string; +}; +declare let c: { + a: string | undefined; +}; +declare let d: { + a?: string | undefined; +}; +declare let t: boolean; +declare let a1: { + a: string; +}; +declare let b1: { + a: string | number; +}; +declare let c1: { + a: string | undefined; +}; +declare let d1: { + a: string | number | undefined; +}; +declare let a2: { + a: string | number; +}; +declare let b2: { + a: string | number; +}; +declare let c2: { + a: string | number | undefined; +}; +declare let d2: { + a: string | number | undefined; +}; diff --git a/tests/baselines/reference/spreadDuplicateExact.symbols b/tests/baselines/reference/spreadDuplicateExact.symbols new file mode 100644 index 0000000000000..f61e1f242b0fd --- /dev/null +++ b/tests/baselines/reference/spreadDuplicateExact.symbols @@ -0,0 +1,66 @@ +=== tests/cases/conformance/types/spread/spreadDuplicateExact.ts === +// Repro from #44438 + +declare let a: { a: string }; +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 2, 11)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 2, 16)) + +declare let b: { a?: string }; +>b : Symbol(b, Decl(spreadDuplicateExact.ts, 3, 11)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 3, 16)) + +declare let c: { a: string | undefined }; +>c : Symbol(c, Decl(spreadDuplicateExact.ts, 4, 11)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 4, 16)) + +declare let d: { a?: string | undefined }; +>d : Symbol(d, Decl(spreadDuplicateExact.ts, 5, 11)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 5, 16)) + +declare let t: boolean; +>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11)) + +let a1 = { a: 123, ...a }; // string (Error) +>a1 : Symbol(a1, Decl(spreadDuplicateExact.ts, 9, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 9, 10)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 2, 11)) + +let b1 = { a: 123, ...b }; // string | number +>b1 : Symbol(b1, Decl(spreadDuplicateExact.ts, 10, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 10, 10)) +>b : Symbol(b, Decl(spreadDuplicateExact.ts, 3, 11)) + +let c1 = { a: 123, ...c }; // string | undefined (Error) +>c1 : Symbol(c1, Decl(spreadDuplicateExact.ts, 11, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 11, 10)) +>c : Symbol(c, Decl(spreadDuplicateExact.ts, 4, 11)) + +let d1 = { a: 123, ...d }; // string | number | undefined +>d1 : Symbol(d1, Decl(spreadDuplicateExact.ts, 12, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 12, 10)) +>d : Symbol(d, Decl(spreadDuplicateExact.ts, 5, 11)) + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +>a2 : Symbol(a2, Decl(spreadDuplicateExact.ts, 14, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 14, 10)) +>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 2, 11)) + +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +>b2 : Symbol(b2, Decl(spreadDuplicateExact.ts, 15, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 15, 10)) +>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11)) +>b : Symbol(b, Decl(spreadDuplicateExact.ts, 3, 11)) + +let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined +>c2 : Symbol(c2, Decl(spreadDuplicateExact.ts, 16, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 16, 10)) +>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11)) +>c : Symbol(c, Decl(spreadDuplicateExact.ts, 4, 11)) + +let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined +>d2 : Symbol(d2, Decl(spreadDuplicateExact.ts, 17, 3)) +>a : Symbol(a, Decl(spreadDuplicateExact.ts, 17, 10)) +>t : Symbol(t, Decl(spreadDuplicateExact.ts, 7, 11)) +>d : Symbol(d, Decl(spreadDuplicateExact.ts, 5, 11)) + diff --git a/tests/baselines/reference/spreadDuplicateExact.types b/tests/baselines/reference/spreadDuplicateExact.types new file mode 100644 index 0000000000000..a4b11003747cb --- /dev/null +++ b/tests/baselines/reference/spreadDuplicateExact.types @@ -0,0 +1,94 @@ +=== tests/cases/conformance/types/spread/spreadDuplicateExact.ts === +// Repro from #44438 + +declare let a: { a: string }; +>a : { a: string; } +>a : string + +declare let b: { a?: string }; +>b : { a?: string; } +>a : string | undefined + +declare let c: { a: string | undefined }; +>c : { a: string | undefined; } +>a : string | undefined + +declare let d: { a?: string | undefined }; +>d : { a?: string | undefined; } +>a : string | undefined + +declare let t: boolean; +>t : boolean + +let a1 = { a: 123, ...a }; // string (Error) +>a1 : { a: string; } +>{ a: 123, ...a } : { a: string; } +>a : number +>123 : 123 +>a : { a: string; } + +let b1 = { a: 123, ...b }; // string | number +>b1 : { a: string | number; } +>{ a: 123, ...b } : { a: string | number; } +>a : number +>123 : 123 +>b : { a?: string; } + +let c1 = { a: 123, ...c }; // string | undefined (Error) +>c1 : { a: string | undefined; } +>{ a: 123, ...c } : { a: string | undefined; } +>a : number +>123 : 123 +>c : { a: string | undefined; } + +let d1 = { a: 123, ...d }; // string | number | undefined +>d1 : { a: string | number | undefined; } +>{ a: 123, ...d } : { a: string | number | undefined; } +>a : number +>123 : 123 +>d : { a?: string | undefined; } + +let a2 = { a: 123, ...(t ? a : {}) }; // string | number +>a2 : { a: string | number; } +>{ a: 123, ...(t ? a : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? a : {}) : { a: string; } | {} +>t ? a : {} : { a: string; } | {} +>t : boolean +>a : { a: string; } +>{} : {} + +let b2 = { a: 123, ...(t ? b : {}) }; // string | number +>b2 : { a: string | number; } +>{ a: 123, ...(t ? b : {}) } : { a: string | number; } +>a : number +>123 : 123 +>(t ? b : {}) : { a?: string; } +>t ? b : {} : { a?: string; } +>t : boolean +>b : { a?: string; } +>{} : {} + +let c2 = { a: 123, ...(t ? c : {}) }; // string | number | undefined +>c2 : { a: string | number | undefined; } +>{ a: 123, ...(t ? c : {}) } : { a: string | number | undefined; } +>a : number +>123 : 123 +>(t ? c : {}) : { a: string | undefined; } | {} +>t ? c : {} : { a: string | undefined; } | {} +>t : boolean +>c : { a: string | undefined; } +>{} : {} + +let d2 = { a: 123, ...(t ? d : {}) }; // string | number | undefined +>d2 : { a: string | number | undefined; } +>{ a: 123, ...(t ? d : {}) } : { a: string | number | undefined; } +>a : number +>123 : 123 +>(t ? d : {}) : { a?: string | undefined; } +>t ? d : {} : { a?: string | undefined; } +>t : boolean +>d : { a?: string | undefined; } +>{} : {} +