diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e7befc3a4d..eff003dbcd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22090,8 +22090,13 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); + propertiesArray = []; + propertiesTable = createSymbolTable(); + hasComputedStringProperty = false; + hasComputedNumberProperty = false; } - return spread; + // remap the raw emptyObjectType fed in at the top into a fresh empty object literal type, unique to this use site + return mapType(spread, t => t === emptyObjectType ? createObjectLiteralType() : t); } return createObjectLiteralType(); diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 827dd76115..aa083e5d9f 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -293,7 +293,7 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { } let o2 = { ...b && { x: 21 }} >o2 : {} ->{ ...b && { x: 21 }} : {} | { x: number; } +>{ ...b && { x: 21 }} : { x: number; } | {} >b && { x: 21 } : false | { x: number; } >b : boolean >{ x: 21 } : { x: number; } @@ -334,7 +334,7 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { } let o2 = { ...nt && { x: nt }} >o2 : {} ->{ ...nt && { x: nt }} : {} | { x: number; } +>{ ...nt && { x: nt }} : { x: number; } | {} >nt && { x: nt } : 0 | { x: number; } >nt : number >{ x: nt } : { x: number; } @@ -375,7 +375,7 @@ function conditionalSpreadString(st: string): { x: string, y: number } { } let o2 = { ...st && { x: st }} >o2 : {} ->{ ...st && { x: st }} : {} | { x: string; } +>{ ...st && { x: st }} : { x: string; } | {} >st && { x: st } : "" | { x: string; } >st : string >{ x: st } : { x: string; } diff --git a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.js b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.js new file mode 100644 index 0000000000..0dfe09cf75 --- /dev/null +++ b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.js @@ -0,0 +1,37 @@ +//// [spreadOfObjectLiteralAssignableToIndexSignature.ts] +const foo: Record = {} // OK + +interface RecordOfRecords extends Record {} +const recordOfRecords: RecordOfRecords = {} +recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK +recordOfRecords.propB = {...(foo && {foo})} // OK +recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK + +interface RecordOfRecordsOrEmpty extends Record {} +const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} +recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK +recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK +recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK + +//// [spreadOfObjectLiteralAssignableToIndexSignature.js] +"use strict"; +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 foo = {}; // OK +var recordOfRecords = {}; +recordOfRecords.propA = __assign({}, (foo !== undefined ? { foo: foo } : {})); // OK +recordOfRecords.propB = __assign({}, (foo && { foo: foo })); // OK +recordOfRecords.propC = __assign({}, (foo !== undefined && { foo: foo })); // error'd in 3.7 beta, should be OK +var recordsOfRecordsOrEmpty = {}; +recordsOfRecordsOrEmpty.propA = __assign({}, (foo !== undefined ? { foo: foo } : {})); // OK +recordsOfRecordsOrEmpty.propB = __assign({}, (foo && { foo: foo })); // OK +recordsOfRecordsOrEmpty.propC = __assign({}, (foo !== undefined && { foo: foo })); // OK diff --git a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.symbols b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.symbols new file mode 100644 index 0000000000..64881726d1 --- /dev/null +++ b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.symbols @@ -0,0 +1,57 @@ +=== tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts === +const foo: Record = {} // OK +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + +interface RecordOfRecords extends Record {} +>RecordOfRecords : Symbol(RecordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 36)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>RecordOfRecords : Symbol(RecordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 36)) + +const recordOfRecords: RecordOfRecords = {} +>recordOfRecords : Symbol(recordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 3, 5)) +>RecordOfRecords : Symbol(RecordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 36)) + +recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK +>recordOfRecords : Symbol(recordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 3, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>undefined : Symbol(undefined) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 4, 50)) + +recordOfRecords.propB = {...(foo && {foo})} // OK +>recordOfRecords : Symbol(recordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 3, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 5, 37)) + +recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK +>recordOfRecords : Symbol(recordOfRecords, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 3, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>undefined : Symbol(undefined) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 6, 51)) + +interface RecordOfRecordsOrEmpty extends Record {} +>RecordOfRecordsOrEmpty : Symbol(RecordOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 6, 57)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>RecordOfRecordsOrEmpty : Symbol(RecordOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 6, 57)) + +const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} +>recordsOfRecordsOrEmpty : Symbol(recordsOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 9, 5)) +>RecordOfRecordsOrEmpty : Symbol(RecordOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 6, 57)) + +recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK +>recordsOfRecordsOrEmpty : Symbol(recordsOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 9, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>undefined : Symbol(undefined) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 10, 58)) + +recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK +>recordsOfRecordsOrEmpty : Symbol(recordsOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 9, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 11, 45)) + +recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK +>recordsOfRecordsOrEmpty : Symbol(recordsOfRecordsOrEmpty, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 9, 5)) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5)) +>undefined : Symbol(undefined) +>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 12, 59)) + diff --git a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types new file mode 100644 index 0000000000..672170acbc --- /dev/null +++ b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types @@ -0,0 +1,97 @@ +=== tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts === +const foo: Record = {} // OK +>foo : Record +>{} : {} + +interface RecordOfRecords extends Record {} +const recordOfRecords: RecordOfRecords = {} +>recordOfRecords : RecordOfRecords +>{} : {} + +recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK +>recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>recordOfRecords.propA : RecordOfRecords +>recordOfRecords : RecordOfRecords +>propA : RecordOfRecords +>{...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>(foo !== undefined ? {foo} : {}) : { foo: Record; } | {} +>foo !== undefined ? {foo} : {} : { foo: Record; } | {} +>foo !== undefined : boolean +>foo : Record +>undefined : undefined +>{foo} : { foo: Record; } +>foo : Record +>{} : {} + +recordOfRecords.propB = {...(foo && {foo})} // OK +>recordOfRecords.propB = {...(foo && {foo})} : { foo: Record; } +>recordOfRecords.propB : RecordOfRecords +>recordOfRecords : RecordOfRecords +>propB : RecordOfRecords +>{...(foo && {foo})} : { foo: Record; } +>(foo && {foo}) : { foo: Record; } +>foo && {foo} : { foo: Record; } +>foo : Record +>{foo} : { foo: Record; } +>foo : Record + +recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK +>recordOfRecords.propC = {...(foo !== undefined && {foo})} : { foo: Record; } | {} +>recordOfRecords.propC : RecordOfRecords +>recordOfRecords : RecordOfRecords +>propC : RecordOfRecords +>{...(foo !== undefined && {foo})} : { foo: Record; } | {} +>(foo !== undefined && {foo}) : false | { foo: Record; } +>foo !== undefined && {foo} : false | { foo: Record; } +>foo !== undefined : boolean +>foo : Record +>undefined : undefined +>{foo} : { foo: Record; } +>foo : Record + +interface RecordOfRecordsOrEmpty extends Record {} +const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} +>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty +>{} : {} + +recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK +>recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>recordsOfRecordsOrEmpty.propA : {} | RecordOfRecordsOrEmpty +>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty +>propA : {} | RecordOfRecordsOrEmpty +>{...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>(foo !== undefined ? {foo} : {}) : { foo: Record; } | {} +>foo !== undefined ? {foo} : {} : { foo: Record; } | {} +>foo !== undefined : boolean +>foo : Record +>undefined : undefined +>{foo} : { foo: Record; } +>foo : Record +>{} : {} + +recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK +>recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} : { foo: Record; } +>recordsOfRecordsOrEmpty.propB : {} | RecordOfRecordsOrEmpty +>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty +>propB : {} | RecordOfRecordsOrEmpty +>{...(foo && {foo})} : { foo: Record; } +>(foo && {foo}) : { foo: Record; } +>foo && {foo} : { foo: Record; } +>foo : Record +>{foo} : { foo: Record; } +>foo : Record + +recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK +>recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo: Record; } | {} +>recordsOfRecordsOrEmpty.propC : {} | RecordOfRecordsOrEmpty +>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty +>propC : {} | RecordOfRecordsOrEmpty +>{...(foo !== undefined && {foo})} : { foo: Record; } | {} +>(foo !== undefined && {foo}) : false | { foo: Record; } +>foo !== undefined && {foo} : false | { foo: Record; } +>foo !== undefined : boolean +>foo : Record +>undefined : undefined +>{foo} : { foo: Record; } +>foo : Record + diff --git a/tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts b/tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts new file mode 100644 index 0000000000..7fa245f93e --- /dev/null +++ b/tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts @@ -0,0 +1,14 @@ +// @strict: true +const foo: Record = {} // OK + +interface RecordOfRecords extends Record {} +const recordOfRecords: RecordOfRecords = {} +recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK +recordOfRecords.propB = {...(foo && {foo})} // OK +recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK + +interface RecordOfRecordsOrEmpty extends Record {} +const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} +recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK +recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK +recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK \ No newline at end of file