Map stale empty object type in union into fresh empty object type after spread is complete (#34839)
* Map stale empty object type in union into fresh empty object type after spread is complete * Accept minor baseline diff
This commit is contained in:
parent
0d993ac592
commit
a6d44aa52e
6 changed files with 214 additions and 4 deletions
|
@ -22090,8 +22090,13 @@ namespace ts {
|
||||||
if (spread !== emptyObjectType) {
|
if (spread !== emptyObjectType) {
|
||||||
if (propertiesArray.length > 0) {
|
if (propertiesArray.length > 0) {
|
||||||
spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext);
|
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();
|
return createObjectLiteralType();
|
||||||
|
|
|
@ -293,7 +293,7 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } {
|
||||||
}
|
}
|
||||||
let o2 = { ...b && { x: 21 }}
|
let o2 = { ...b && { x: 21 }}
|
||||||
>o2 : {}
|
>o2 : {}
|
||||||
>{ ...b && { x: 21 }} : {} | { x: number; }
|
>{ ...b && { x: 21 }} : { x: number; } | {}
|
||||||
>b && { x: 21 } : false | { x: number; }
|
>b && { x: 21 } : false | { x: number; }
|
||||||
>b : boolean
|
>b : boolean
|
||||||
>{ x: 21 } : { x: number; }
|
>{ x: 21 } : { x: number; }
|
||||||
|
@ -334,7 +334,7 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } {
|
||||||
}
|
}
|
||||||
let o2 = { ...nt && { x: nt }}
|
let o2 = { ...nt && { x: nt }}
|
||||||
>o2 : {}
|
>o2 : {}
|
||||||
>{ ...nt && { x: nt }} : {} | { x: number; }
|
>{ ...nt && { x: nt }} : { x: number; } | {}
|
||||||
>nt && { x: nt } : 0 | { x: number; }
|
>nt && { x: nt } : 0 | { x: number; }
|
||||||
>nt : number
|
>nt : number
|
||||||
>{ x: nt } : { x: number; }
|
>{ x: nt } : { x: number; }
|
||||||
|
@ -375,7 +375,7 @@ function conditionalSpreadString(st: string): { x: string, y: number } {
|
||||||
}
|
}
|
||||||
let o2 = { ...st && { x: st }}
|
let o2 = { ...st && { x: st }}
|
||||||
>o2 : {}
|
>o2 : {}
|
||||||
>{ ...st && { x: st }} : {} | { x: string; }
|
>{ ...st && { x: st }} : { x: string; } | {}
|
||||||
>st && { x: st } : "" | { x: string; }
|
>st && { x: st } : "" | { x: string; }
|
||||||
>st : string
|
>st : string
|
||||||
>{ x: st } : { x: string; }
|
>{ x: st } : { x: string; }
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
//// [spreadOfObjectLiteralAssignableToIndexSignature.ts]
|
||||||
|
const foo: Record<never, never> = {} // OK
|
||||||
|
|
||||||
|
interface RecordOfRecords extends Record<keyof any, RecordOfRecords> {}
|
||||||
|
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<keyof any, RecordOfRecordsOrEmpty | {}> {}
|
||||||
|
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
|
|
@ -0,0 +1,57 @@
|
||||||
|
=== tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts ===
|
||||||
|
const foo: Record<never, never> = {} // OK
|
||||||
|
>foo : Symbol(foo, Decl(spreadOfObjectLiteralAssignableToIndexSignature.ts, 0, 5))
|
||||||
|
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||||
|
|
||||||
|
interface RecordOfRecords extends Record<keyof any, RecordOfRecords> {}
|
||||||
|
>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<keyof any, RecordOfRecordsOrEmpty | {}> {}
|
||||||
|
>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))
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
=== tests/cases/compiler/spreadOfObjectLiteralAssignableToIndexSignature.ts ===
|
||||||
|
const foo: Record<never, never> = {} // OK
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>{} : {}
|
||||||
|
|
||||||
|
interface RecordOfRecords extends Record<keyof any, RecordOfRecords> {}
|
||||||
|
const recordOfRecords: RecordOfRecords = {}
|
||||||
|
>recordOfRecords : RecordOfRecords
|
||||||
|
>{} : {}
|
||||||
|
|
||||||
|
recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK
|
||||||
|
>recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record<never, never>; } | {}
|
||||||
|
>recordOfRecords.propA : RecordOfRecords
|
||||||
|
>recordOfRecords : RecordOfRecords
|
||||||
|
>propA : RecordOfRecords
|
||||||
|
>{...(foo !== undefined ? {foo} : {})} : { foo: Record<never, never>; } | {}
|
||||||
|
>(foo !== undefined ? {foo} : {}) : { foo: Record<never, never>; } | {}
|
||||||
|
>foo !== undefined ? {foo} : {} : { foo: Record<never, never>; } | {}
|
||||||
|
>foo !== undefined : boolean
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>undefined : undefined
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>{} : {}
|
||||||
|
|
||||||
|
recordOfRecords.propB = {...(foo && {foo})} // OK
|
||||||
|
>recordOfRecords.propB = {...(foo && {foo})} : { foo: Record<never, never>; }
|
||||||
|
>recordOfRecords.propB : RecordOfRecords
|
||||||
|
>recordOfRecords : RecordOfRecords
|
||||||
|
>propB : RecordOfRecords
|
||||||
|
>{...(foo && {foo})} : { foo: Record<never, never>; }
|
||||||
|
>(foo && {foo}) : { foo: Record<never, never>; }
|
||||||
|
>foo && {foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
|
||||||
|
recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK
|
||||||
|
>recordOfRecords.propC = {...(foo !== undefined && {foo})} : { foo: Record<never, never>; } | {}
|
||||||
|
>recordOfRecords.propC : RecordOfRecords
|
||||||
|
>recordOfRecords : RecordOfRecords
|
||||||
|
>propC : RecordOfRecords
|
||||||
|
>{...(foo !== undefined && {foo})} : { foo: Record<never, never>; } | {}
|
||||||
|
>(foo !== undefined && {foo}) : false | { foo: Record<never, never>; }
|
||||||
|
>foo !== undefined && {foo} : false | { foo: Record<never, never>; }
|
||||||
|
>foo !== undefined : boolean
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>undefined : undefined
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
|
||||||
|
interface RecordOfRecordsOrEmpty extends Record<keyof any, RecordOfRecordsOrEmpty | {}> {}
|
||||||
|
const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {}
|
||||||
|
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
|
||||||
|
>{} : {}
|
||||||
|
|
||||||
|
recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK
|
||||||
|
>recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record<never, never>; } | {}
|
||||||
|
>recordsOfRecordsOrEmpty.propA : {} | RecordOfRecordsOrEmpty
|
||||||
|
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
|
||||||
|
>propA : {} | RecordOfRecordsOrEmpty
|
||||||
|
>{...(foo !== undefined ? {foo} : {})} : { foo: Record<never, never>; } | {}
|
||||||
|
>(foo !== undefined ? {foo} : {}) : { foo: Record<never, never>; } | {}
|
||||||
|
>foo !== undefined ? {foo} : {} : { foo: Record<never, never>; } | {}
|
||||||
|
>foo !== undefined : boolean
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>undefined : undefined
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>{} : {}
|
||||||
|
|
||||||
|
recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK
|
||||||
|
>recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} : { foo: Record<never, never>; }
|
||||||
|
>recordsOfRecordsOrEmpty.propB : {} | RecordOfRecordsOrEmpty
|
||||||
|
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
|
||||||
|
>propB : {} | RecordOfRecordsOrEmpty
|
||||||
|
>{...(foo && {foo})} : { foo: Record<never, never>; }
|
||||||
|
>(foo && {foo}) : { foo: Record<never, never>; }
|
||||||
|
>foo && {foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
|
||||||
|
recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK
|
||||||
|
>recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo: Record<never, never>; } | {}
|
||||||
|
>recordsOfRecordsOrEmpty.propC : {} | RecordOfRecordsOrEmpty
|
||||||
|
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
|
||||||
|
>propC : {} | RecordOfRecordsOrEmpty
|
||||||
|
>{...(foo !== undefined && {foo})} : { foo: Record<never, never>; } | {}
|
||||||
|
>(foo !== undefined && {foo}) : false | { foo: Record<never, never>; }
|
||||||
|
>foo !== undefined && {foo} : false | { foo: Record<never, never>; }
|
||||||
|
>foo !== undefined : boolean
|
||||||
|
>foo : Record<never, never>
|
||||||
|
>undefined : undefined
|
||||||
|
>{foo} : { foo: Record<never, never>; }
|
||||||
|
>foo : Record<never, never>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// @strict: true
|
||||||
|
const foo: Record<never, never> = {} // OK
|
||||||
|
|
||||||
|
interface RecordOfRecords extends Record<keyof any, RecordOfRecords> {}
|
||||||
|
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<keyof any, RecordOfRecordsOrEmpty | {}> {}
|
||||||
|
const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {}
|
||||||
|
recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK
|
||||||
|
recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK
|
||||||
|
recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK
|
Loading…
Reference in a new issue