Do for unions of many empty-object-spreadables what we did for unions of 2 (#42233)

* Do for unions of many empty-object-spreadables what we did for unions of 2

* Accept baseline
This commit is contained in:
Wesley Wigham 2021-01-07 12:05:40 -08:00 committed by GitHub
parent dbba8b358f
commit 11606e4de4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 281 additions and 58 deletions

View file

@ -14670,19 +14670,18 @@ namespace ts {
}
function tryMergeUnionOfObjectTypeAndEmptyObject(type: UnionType, readonly: boolean): Type | undefined {
if (type.types.length === 2) {
const firstType = type.types[0];
const secondType = type.types[1];
if (every(type.types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) {
return isEmptyObjectType(firstType) ? firstType : isEmptyObjectType(secondType) ? secondType : emptyObjectType;
}
if (isEmptyObjectTypeOrSpreadsIntoEmptyObject(firstType)) {
return getAnonymousPartialType(secondType);
}
if (isEmptyObjectTypeOrSpreadsIntoEmptyObject(secondType)) {
return getAnonymousPartialType(firstType);
}
if (every(type.types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) {
return find(type.types, isEmptyObjectType) || emptyObjectType;
}
const firstType = find(type.types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t));
if (!firstType) {
return undefined;
}
const secondType = firstType && find(type.types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t));
if (secondType) {
return undefined;
}
return getAnonymousPartialType(firstType);
function getAnonymousPartialType(type: Type) {
// gets the type as if it had been spread, but where everything in the spread is made optional
@ -14695,7 +14694,7 @@ namespace ts {
const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
const flags = SymbolFlags.Property | SymbolFlags.Optional;
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.type = isSetonlyAccessor ? undefinedType : getUnionType([getTypeOfSymbol(prop), undefinedType]);
result.declarations = prop.declarations;
result.nameType = getSymbolLinks(prop).nameType;
result.syntheticOrigin = prop;

View file

@ -229,8 +229,8 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } {
>14 : 14
}
let o2 = { ...b && { x: 21 }}
>o2 : { x?: number; }
>{ ...b && { x: 21 }} : { x?: number; }
>o2 : { x?: number | undefined; }
>{ ...b && { x: 21 }} : { x?: number | undefined; }
>b && { x: 21 } : false | { x: number; }
>b : boolean
>{ x: 21 } : { x: number; }
@ -270,8 +270,8 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } {
>nt : number
}
let o2 = { ...nt && { x: nt }}
>o2 : { x?: number; }
>{ ...nt && { x: nt }} : { x?: number; }
>o2 : { x?: number | undefined; }
>{ ...nt && { x: nt }} : { x?: number | undefined; }
>nt && { x: nt } : 0 | { x: number; }
>nt : number
>{ x: nt } : { x: number; }
@ -311,8 +311,8 @@ function conditionalSpreadString(st: string): { x: string, y: number } {
>st : string
}
let o2 = { ...st && { x: st }}
>o2 : { x?: string; }
>{ ...st && { x: st }} : { x?: string; }
>o2 : { x?: string | undefined; }
>{ ...st && { x: st }} : { x?: string | undefined; }
>st && { x: st } : "" | { x: string; }
>st : string
>{ x: st } : { x: string; }

View file

@ -1,11 +1,11 @@
=== tests/cases/conformance/types/spread/objectSpreadRepeatedComplexity.ts ===
function f(cnd: Record<number, boolean>){
>f : (cnd: Record<number, boolean>) => { prop20a?: number; prop20b?: number; prop19a?: number; prop19b?: number; prop18a?: number; prop18b?: number; prop17a?: number; prop17b?: number; prop16a?: number; prop16b?: number; prop15a?: number; prop15b?: number; prop14a?: number; prop14b?: number; prop13a?: number; prop13b?: number; prop12a?: number; prop12b?: number; prop11a?: number; prop11b?: number; prop10a?: number; prop10b?: number; prop9a?: number; prop9b?: number; prop8a?: number; prop8b?: number; prop7a?: number; prop7b?: number; prop6a?: number; prop6b?: number; prop5a?: number; prop5b?: number; prop4a?: number; prop4b?: number; prop3a?: number; prop3b?: number; prop0?: number; }
>f : (cnd: Record<number, boolean>) => { prop20a?: number | undefined; prop20b?: number | undefined; prop19a?: number | undefined; prop19b?: number | undefined; prop18a?: number | undefined; prop18b?: number | undefined; prop17a?: number | undefined; prop17b?: number | undefined; prop16a?: number | undefined; prop16b?: number | undefined; prop15a?: number | undefined; prop15b?: number | undefined; prop14a?: number | undefined; prop14b?: number | undefined; prop13a?: number | undefined; prop13b?: number | undefined; prop12a?: number | undefined; prop12b?: number | undefined; prop11a?: number | undefined; prop11b?: number | undefined; prop10a?: number | undefined; prop10b?: number | undefined; prop9a?: number | undefined; prop9b?: number | undefined; prop8a?: number | undefined; prop8b?: number | undefined; prop7a?: number | undefined; prop7b?: number | undefined; prop6a?: number | undefined; prop6b?: number | undefined; prop5a?: number | undefined; prop5b?: number | undefined; prop4a?: number | undefined; prop4b?: number | undefined; prop3a?: number | undefined; prop3b?: number | undefined; prop0?: number | undefined; }
>cnd : Record<number, boolean>
// Type is a union of 2^(n-1) members, where n is the number of spread objects
return {
>{ // Without this one, it collapses to {} ? ...(cnd[1] && cnd[2] && { prop0: 0, }), // With one prop each, it collapses to a single object (#34853?) ...(cnd[3] && { prop3a: 1, prop3b: 1, }), ...(cnd[4] && { prop4a: 1, prop4b: 1, }), ...(cnd[5] && { prop5a: 1, prop5b: 1, }), ...(cnd[6] && { prop6a: 1, prop6b: 1, }), ...(cnd[7] && { prop7a: 1, prop7b: 1, }), ...(cnd[8] && { prop8a: 1, prop8b: 1, }), ...(cnd[9] && { prop9a: 1, prop9b: 1, }), ...(cnd[10] && { prop10a: 1, prop10b: 1, }), ...(cnd[11] && { prop11a: 1, prop11b: 1, }), ...(cnd[12] && { prop12a: 1, prop12b: 1, }), ...(cnd[13] && { prop13a: 1, prop13b: 1, }), ...(cnd[14] && { prop14a: 1, prop14b: 1, }), ...(cnd[15] && { prop15a: 1, prop15b: 1, }), ...(cnd[16] && { prop16a: 1, prop16b: 1, }), ...(cnd[17] && { prop17a: 1, prop17b: 1, }), ...(cnd[18] && { prop18a: 1, prop18b: 1, }), ...(cnd[19] && { prop19a: 1, prop19b: 1, }), ...(cnd[20] && { prop20a: 1, prop20b: 1, }), } : { prop20a?: number; prop20b?: number; prop19a?: number; prop19b?: number; prop18a?: number; prop18b?: number; prop17a?: number; prop17b?: number; prop16a?: number; prop16b?: number; prop15a?: number; prop15b?: number; prop14a?: number; prop14b?: number; prop13a?: number; prop13b?: number; prop12a?: number; prop12b?: number; prop11a?: number; prop11b?: number; prop10a?: number; prop10b?: number; prop9a?: number; prop9b?: number; prop8a?: number; prop8b?: number; prop7a?: number; prop7b?: number; prop6a?: number; prop6b?: number; prop5a?: number; prop5b?: number; prop4a?: number; prop4b?: number; prop3a?: number; prop3b?: number; prop0?: number; }
>{ // Without this one, it collapses to {} ? ...(cnd[1] && cnd[2] && { prop0: 0, }), // With one prop each, it collapses to a single object (#34853?) ...(cnd[3] && { prop3a: 1, prop3b: 1, }), ...(cnd[4] && { prop4a: 1, prop4b: 1, }), ...(cnd[5] && { prop5a: 1, prop5b: 1, }), ...(cnd[6] && { prop6a: 1, prop6b: 1, }), ...(cnd[7] && { prop7a: 1, prop7b: 1, }), ...(cnd[8] && { prop8a: 1, prop8b: 1, }), ...(cnd[9] && { prop9a: 1, prop9b: 1, }), ...(cnd[10] && { prop10a: 1, prop10b: 1, }), ...(cnd[11] && { prop11a: 1, prop11b: 1, }), ...(cnd[12] && { prop12a: 1, prop12b: 1, }), ...(cnd[13] && { prop13a: 1, prop13b: 1, }), ...(cnd[14] && { prop14a: 1, prop14b: 1, }), ...(cnd[15] && { prop15a: 1, prop15b: 1, }), ...(cnd[16] && { prop16a: 1, prop16b: 1, }), ...(cnd[17] && { prop17a: 1, prop17b: 1, }), ...(cnd[18] && { prop18a: 1, prop18b: 1, }), ...(cnd[19] && { prop19a: 1, prop19b: 1, }), ...(cnd[20] && { prop20a: 1, prop20b: 1, }), } : { prop20a?: number | undefined; prop20b?: number | undefined; prop19a?: number | undefined; prop19b?: number | undefined; prop18a?: number | undefined; prop18b?: number | undefined; prop17a?: number | undefined; prop17b?: number | undefined; prop16a?: number | undefined; prop16b?: number | undefined; prop15a?: number | undefined; prop15b?: number | undefined; prop14a?: number | undefined; prop14b?: number | undefined; prop13a?: number | undefined; prop13b?: number | undefined; prop12a?: number | undefined; prop12b?: number | undefined; prop11a?: number | undefined; prop11b?: number | undefined; prop10a?: number | undefined; prop10b?: number | undefined; prop9a?: number | undefined; prop9b?: number | undefined; prop8a?: number | undefined; prop8b?: number | undefined; prop7a?: number | undefined; prop7b?: number | undefined; prop6a?: number | undefined; prop6b?: number | undefined; prop5a?: number | undefined; prop5b?: number | undefined; prop4a?: number | undefined; prop4b?: number | undefined; prop3a?: number | undefined; prop3b?: number | undefined; prop0?: number | undefined; }
// Without this one, it collapses to {} ?
...(cnd[1] &&

View file

@ -84,7 +84,7 @@ function parseWithSpread(config: Record<string, number>): Props {
>config : Record<string, number>
return {
>{ ...config.a !== undefined && { a: config.a.toString() }, ...config.b !== undefined && { b: config.b.toString() }, ...config.c !== undefined && { c: config.c.toString() }, ...config.d !== undefined && { d: config.d.toString() }, ...config.e !== undefined && { e: config.e.toString() }, ...config.f !== undefined && { f: config.f.toString() }, ...config.g !== undefined && { g: config.g.toString() }, ...config.h !== undefined && { h: config.h.toString() }, ...config.i !== undefined && { i: config.i.toString() }, ...config.j !== undefined && { j: config.j.toString() }, ...config.k !== undefined && { k: config.k.toString() }, ...config.l !== undefined && { l: config.l.toString() }, ...config.m !== undefined && { m: config.m.toString() }, ...config.n !== undefined && { n: config.n.toString() }, ...config.o !== undefined && { o: config.o.toString() }, ...config.p !== undefined && { p: config.p.toString() }, ...config.q !== undefined && { q: config.q.toString() }, ...config.r !== undefined && { r: config.r.toString() }, ...config.s !== undefined && { s: config.s.toString() }, ...config.t !== undefined && { t: config.t.toString() }, ...config.u !== undefined && { u: config.u.toString() }, ...config.v !== undefined && { v: config.v.toString() }, ...config.w !== undefined && { w: config.w.toString() }, ...config.x !== undefined && { x: config.x.toString() }, ...config.y !== undefined && { y: config.y.toString() }, ...config.z !== undefined && { z: config.z.toString() } } : { z?: string; y?: string; x?: string; w?: string; v?: string; u?: string; t?: string; s?: string; r?: string; q?: string; p?: string; o?: string; n?: string; m?: string; l?: string; k?: string; j?: string; i?: string; h?: string; g?: string; f?: string; e?: string; d?: string; c?: string; b?: string; a?: string; }
>{ ...config.a !== undefined && { a: config.a.toString() }, ...config.b !== undefined && { b: config.b.toString() }, ...config.c !== undefined && { c: config.c.toString() }, ...config.d !== undefined && { d: config.d.toString() }, ...config.e !== undefined && { e: config.e.toString() }, ...config.f !== undefined && { f: config.f.toString() }, ...config.g !== undefined && { g: config.g.toString() }, ...config.h !== undefined && { h: config.h.toString() }, ...config.i !== undefined && { i: config.i.toString() }, ...config.j !== undefined && { j: config.j.toString() }, ...config.k !== undefined && { k: config.k.toString() }, ...config.l !== undefined && { l: config.l.toString() }, ...config.m !== undefined && { m: config.m.toString() }, ...config.n !== undefined && { n: config.n.toString() }, ...config.o !== undefined && { o: config.o.toString() }, ...config.p !== undefined && { p: config.p.toString() }, ...config.q !== undefined && { q: config.q.toString() }, ...config.r !== undefined && { r: config.r.toString() }, ...config.s !== undefined && { s: config.s.toString() }, ...config.t !== undefined && { t: config.t.toString() }, ...config.u !== undefined && { u: config.u.toString() }, ...config.v !== undefined && { v: config.v.toString() }, ...config.w !== undefined && { w: config.w.toString() }, ...config.x !== undefined && { x: config.x.toString() }, ...config.y !== undefined && { y: config.y.toString() }, ...config.z !== undefined && { z: config.z.toString() } } : { z?: string | undefined; y?: string | undefined; x?: string | undefined; w?: string | undefined; v?: string | undefined; u?: string | undefined; t?: string | undefined; s?: string | undefined; r?: string | undefined; q?: string | undefined; p?: string | undefined; o?: string | undefined; n?: string | undefined; m?: string | undefined; l?: string | undefined; k?: string | undefined; j?: string | undefined; i?: string | undefined; h?: string | undefined; g?: string | undefined; f?: string | undefined; e?: string | undefined; d?: string | undefined; c?: string | undefined; b?: string | undefined; a?: string | undefined; }
...config.a !== undefined && { a: config.a.toString() },
>config.a !== undefined && { a: config.a.toString() } : false | { a: string; }

View file

@ -0,0 +1,48 @@
//// [spreadIdenticalTypesRemoved.ts]
interface Animal {
name: string;
kind: string;
age: number;
location: string;
owner: object;
}
function clonePet(pet: Animal, fullCopy?: boolean) {
return {
name: pet.name,
kind: pet.kind,
...(fullCopy && pet),
}
}
interface Animal2 {
name: string;
owner?: string;
}
function billOwner(pet: Animal2) {
return {
...(pet.owner && pet),
paid: false
}
}
//// [spreadIdenticalTypesRemoved.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);
};
function clonePet(pet, fullCopy) {
return __assign({ name: pet.name, kind: pet.kind }, (fullCopy && pet));
}
function billOwner(pet) {
return __assign(__assign({}, (pet.owner && pet)), { paid: false });
}

View file

@ -0,0 +1,71 @@
=== tests/cases/compiler/spreadIdenticalTypesRemoved.ts ===
interface Animal {
>Animal : Symbol(Animal, Decl(spreadIdenticalTypesRemoved.ts, 0, 0))
name: string;
>name : Symbol(Animal.name, Decl(spreadIdenticalTypesRemoved.ts, 0, 18))
kind: string;
>kind : Symbol(Animal.kind, Decl(spreadIdenticalTypesRemoved.ts, 1, 17))
age: number;
>age : Symbol(Animal.age, Decl(spreadIdenticalTypesRemoved.ts, 2, 17))
location: string;
>location : Symbol(Animal.location, Decl(spreadIdenticalTypesRemoved.ts, 3, 16))
owner: object;
>owner : Symbol(Animal.owner, Decl(spreadIdenticalTypesRemoved.ts, 4, 21))
}
function clonePet(pet: Animal, fullCopy?: boolean) {
>clonePet : Symbol(clonePet, Decl(spreadIdenticalTypesRemoved.ts, 6, 1))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 8, 18))
>Animal : Symbol(Animal, Decl(spreadIdenticalTypesRemoved.ts, 0, 0))
>fullCopy : Symbol(fullCopy, Decl(spreadIdenticalTypesRemoved.ts, 8, 30))
return {
name: pet.name,
>name : Symbol(name, Decl(spreadIdenticalTypesRemoved.ts, 9, 12))
>pet.name : Symbol(Animal.name, Decl(spreadIdenticalTypesRemoved.ts, 0, 18))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 8, 18))
>name : Symbol(Animal.name, Decl(spreadIdenticalTypesRemoved.ts, 0, 18))
kind: pet.kind,
>kind : Symbol(kind, Decl(spreadIdenticalTypesRemoved.ts, 10, 23))
>pet.kind : Symbol(Animal.kind, Decl(spreadIdenticalTypesRemoved.ts, 1, 17))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 8, 18))
>kind : Symbol(Animal.kind, Decl(spreadIdenticalTypesRemoved.ts, 1, 17))
...(fullCopy && pet),
>fullCopy : Symbol(fullCopy, Decl(spreadIdenticalTypesRemoved.ts, 8, 30))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 8, 18))
}
}
interface Animal2 {
>Animal2 : Symbol(Animal2, Decl(spreadIdenticalTypesRemoved.ts, 14, 1))
name: string;
>name : Symbol(Animal2.name, Decl(spreadIdenticalTypesRemoved.ts, 16, 19))
owner?: string;
>owner : Symbol(Animal2.owner, Decl(spreadIdenticalTypesRemoved.ts, 17, 17))
}
function billOwner(pet: Animal2) {
>billOwner : Symbol(billOwner, Decl(spreadIdenticalTypesRemoved.ts, 19, 1))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 20, 19))
>Animal2 : Symbol(Animal2, Decl(spreadIdenticalTypesRemoved.ts, 14, 1))
return {
...(pet.owner && pet),
>pet.owner : Symbol(Animal2.owner, Decl(spreadIdenticalTypesRemoved.ts, 17, 17))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 20, 19))
>owner : Symbol(Animal2.owner, Decl(spreadIdenticalTypesRemoved.ts, 17, 17))
>pet : Symbol(pet, Decl(spreadIdenticalTypesRemoved.ts, 20, 19))
paid: false
>paid : Symbol(paid, Decl(spreadIdenticalTypesRemoved.ts, 22, 30))
}
}

View file

@ -0,0 +1,74 @@
=== tests/cases/compiler/spreadIdenticalTypesRemoved.ts ===
interface Animal {
name: string;
>name : string
kind: string;
>kind : string
age: number;
>age : number
location: string;
>location : string
owner: object;
>owner : object
}
function clonePet(pet: Animal, fullCopy?: boolean) {
>clonePet : (pet: Animal, fullCopy?: boolean | undefined) => { name: string; kind: string; age?: number | undefined; location?: string | undefined; owner?: object | undefined; }
>pet : Animal
>fullCopy : boolean | undefined
return {
>{ name: pet.name, kind: pet.kind, ...(fullCopy && pet), } : { name: string; kind: string; age?: number | undefined; location?: string | undefined; owner?: object | undefined; }
name: pet.name,
>name : string
>pet.name : string
>pet : Animal
>name : string
kind: pet.kind,
>kind : string
>pet.kind : string
>pet : Animal
>kind : string
...(fullCopy && pet),
>(fullCopy && pet) : false | Animal | undefined
>fullCopy && pet : false | Animal | undefined
>fullCopy : boolean | undefined
>pet : Animal
}
}
interface Animal2 {
name: string;
>name : string
owner?: string;
>owner : string | undefined
}
function billOwner(pet: Animal2) {
>billOwner : (pet: Animal2) => { paid: boolean; name?: string | undefined; owner?: string | undefined; }
>pet : Animal2
return {
>{ ...(pet.owner && pet), paid: false } : { paid: boolean; name?: string | undefined; owner?: string | undefined; }
...(pet.owner && pet),
>(pet.owner && pet) : "" | Animal2 | undefined
>pet.owner && pet : "" | Animal2 | undefined
>pet.owner : string | undefined
>pet : Animal2
>owner : string | undefined
>pet : Animal2
paid: false
>paid : boolean
>false : false
}
}

View file

@ -9,11 +9,11 @@ const recordOfRecords: RecordOfRecords = {}
>{} : {}
recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK
>recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never>; }
>recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never> | undefined; }
>recordOfRecords.propA : RecordOfRecords
>recordOfRecords : RecordOfRecords
>propA : RecordOfRecords
>{...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never>; }
>{...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never> | undefined; }
>(foo !== undefined ? {foo} : {}) : { foo: Record<never, never>; } | {}
>foo !== undefined ? {foo} : {} : { foo: Record<never, never>; } | {}
>foo !== undefined : boolean
@ -36,11 +36,11 @@ recordOfRecords.propB = {...(foo && {foo})} // OK
>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 = {...(foo !== undefined && {foo})} : { foo?: Record<never, never> | undefined; }
>recordOfRecords.propC : RecordOfRecords
>recordOfRecords : RecordOfRecords
>propC : RecordOfRecords
>{...(foo !== undefined && {foo})} : { foo?: Record<never, never>; }
>{...(foo !== undefined && {foo})} : { foo?: Record<never, never> | undefined; }
>(foo !== undefined && {foo}) : false | { foo: Record<never, never>; }
>foo !== undefined && {foo} : false | { foo: Record<never, never>; }
>foo !== undefined : boolean
@ -55,11 +55,11 @@ const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {}
>{} : {}
recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK
>recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never>; }
>recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never> | undefined; }
>recordsOfRecordsOrEmpty.propA : {} | RecordOfRecordsOrEmpty
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
>propA : {} | RecordOfRecordsOrEmpty
>{...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never>; }
>{...(foo !== undefined ? {foo} : {})} : { foo?: Record<never, never> | undefined; }
>(foo !== undefined ? {foo} : {}) : { foo: Record<never, never>; } | {}
>foo !== undefined ? {foo} : {} : { foo: Record<never, never>; } | {}
>foo !== undefined : boolean
@ -82,11 +82,11 @@ recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK
>foo : Record<never, never>
recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK
>recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo?: Record<never, never>; }
>recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo?: Record<never, never> | undefined; }
>recordsOfRecordsOrEmpty.propC : {} | RecordOfRecordsOrEmpty
>recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty
>propC : {} | RecordOfRecordsOrEmpty
>{...(foo !== undefined && {foo})} : { foo?: Record<never, never>; }
>{...(foo !== undefined && {foo})} : { foo?: Record<never, never> | undefined; }
>(foo !== undefined && {foo}) : false | { foo: Record<never, never>; }
>foo !== undefined && {foo} : false | { foo: Record<never, never>; }
>foo !== undefined : boolean

View file

@ -78,14 +78,14 @@ function h(obj: { x: number } | { x: string }) {
>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; }
>i : (b: boolean, t: { command: string; ok: string;}) => { command: string; ok?: string | undefined; }
>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: "hi", ...(b ? t : {}) } : { command: string; ok?: string | undefined; }
>command : string
>"hi" : "hi"
>(b ? t : {}) : { command: string; ok: string; } | {}

View file

@ -1,9 +1,9 @@
tests/cases/conformance/types/spread/spreadUnion2.ts(5,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(8,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ b?: number; a?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(12,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ a?: number; b?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(18,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(5,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' must be of type '{} | { a: number; }', but here has type '{ a?: number | undefined; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(8,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' must be of type '{} | { b: number; }', but here has type '{ b?: number | undefined; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ b?: number | undefined; a?: number | undefined; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(12,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ a?: number | undefined; b?: number | undefined; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' must be of type '{} | { a: number; }', but here has type '{ a?: number | undefined; }'.
tests/cases/conformance/types/spread/spreadUnion2.ts(18,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' must be of type '{} | { b: number; }', but here has type '{ b?: number | undefined; }'.
==== tests/cases/conformance/types/spread/spreadUnion2.ts (6 errors) ====
@ -13,35 +13,35 @@ tests/cases/conformance/types/spread/spreadUnion2.ts(18,5): error TS2403: Subseq
var o1: {} | { a: number };
var o1 = { ...undefinedUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' must be of type '{} | { a: number; }', but here has type '{ a?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:4:5: 'o1' was also declared here.
var o2: {} | { b: number };
var o2 = { ...nullUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' must be of type '{} | { b: number; }', but here has type '{ b?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:7:5: 'o2' was also declared here.
var o3: {} | { a: number } | { b: number } | { a: number, b: number };
var o3 = { ...undefinedUnion, ...nullUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ b?: number; a?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ b?: number | undefined; a?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:10:5: 'o3' was also declared here.
var o3 = { ...nullUnion, ...undefinedUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ a?: number; b?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' must be of type '{} | { a: number; } | { b: number; } | { a: number; b: number; }', but here has type '{ a?: number | undefined; b?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:10:5: 'o3' was also declared here.
var o4: {} | { a: number };
var o4 = { ...undefinedUnion, ...undefinedUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' must be of type '{} | { a: number; }', but here has type '{ a?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:14:5: 'o4' was also declared here.
var o5: {} | { b: number };
var o5 = { ...nullUnion, ...nullUnion };
~~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' must be of type '{} | { b: number; }', but here has type '{ b?: number | undefined; }'.
!!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:17:5: 'o5' was also declared here.

View file

@ -14,7 +14,7 @@ var o1: {} | { a: number };
var o1 = { ...undefinedUnion };
>o1 : {} | { a: number; }
>{ ...undefinedUnion } : { a?: number; }
>{ ...undefinedUnion } : { a?: number | undefined; }
>undefinedUnion : { a: number; } | undefined
var o2: {} | { b: number };
@ -23,7 +23,7 @@ var o2: {} | { b: number };
var o2 = { ...nullUnion };
>o2 : {} | { b: number; }
>{ ...nullUnion } : { b?: number; }
>{ ...nullUnion } : { b?: number | undefined; }
>nullUnion : { b: number; } | null
var o3: {} | { a: number } | { b: number } | { a: number, b: number };
@ -35,13 +35,13 @@ var o3: {} | { a: number } | { b: number } | { a: number, b: number };
var o3 = { ...undefinedUnion, ...nullUnion };
>o3 : {} | { a: number; } | { b: number; } | { a: number; b: number; }
>{ ...undefinedUnion, ...nullUnion } : { b?: number; a?: number; }
>{ ...undefinedUnion, ...nullUnion } : { b?: number | undefined; a?: number | undefined; }
>undefinedUnion : { a: number; } | undefined
>nullUnion : { b: number; } | null
var o3 = { ...nullUnion, ...undefinedUnion };
>o3 : {} | { a: number; } | { b: number; } | { a: number; b: number; }
>{ ...nullUnion, ...undefinedUnion } : { a?: number; b?: number; }
>{ ...nullUnion, ...undefinedUnion } : { a?: number | undefined; b?: number | undefined; }
>nullUnion : { b: number; } | null
>undefinedUnion : { a: number; } | undefined
@ -51,7 +51,7 @@ var o4: {} | { a: number };
var o4 = { ...undefinedUnion, ...undefinedUnion };
>o4 : {} | { a: number; }
>{ ...undefinedUnion, ...undefinedUnion } : { a?: number; }
>{ ...undefinedUnion, ...undefinedUnion } : { a?: number | undefined; }
>undefinedUnion : { a: number; } | undefined
>undefinedUnion : { a: number; } | undefined
@ -61,7 +61,7 @@ var o5: {} | { b: number };
var o5 = { ...nullUnion, ...nullUnion };
>o5 : {} | { b: number; }
>{ ...nullUnion, ...nullUnion } : { b?: number; }
>{ ...nullUnion, ...nullUnion } : { b?: number | undefined; }
>nullUnion : { b: number; } | null
>nullUnion : { b: number; } | null

View file

@ -1,5 +1,6 @@
tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{}'.
tests/cases/conformance/types/spread/spreadUnion3.ts(9,9): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types.
@ -17,8 +18,9 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Sprea
function g(t?: { a: number } | null): void {
let b = { ...t };
let c: number = b.a; // might not have 'a'
~
!!! error TS2339: Property 'a' does not exist on type '{}'.
~
!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'.
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
}
g()
g(undefined)

View file

@ -25,7 +25,9 @@ function g(t?: { a: number } | null): void {
let c: number = b.a; // might not have 'a'
>c : Symbol(c, Decl(spreadUnion3.ts, 8, 7))
>b.a : Symbol(a, Decl(spreadUnion3.ts, 6, 16))
>b : Symbol(b, Decl(spreadUnion3.ts, 7, 7))
>a : Symbol(a, Decl(spreadUnion3.ts, 6, 16))
}
g()
>g : Symbol(g, Decl(spreadUnion3.ts, 3, 12))

View file

@ -24,15 +24,15 @@ function g(t?: { a: number } | null): void {
>null : null
let b = { ...t };
>b : {}
>{ ...t } : {} | {} | { a: number; }
>b : { a?: number | undefined; }
>{ ...t } : { a?: number | undefined; }
>t : { a: number; } | null | undefined
let c: number = b.a; // might not have 'a'
>c : number
>b.a : any
>b : {}
>a : any
>b.a : number | undefined
>b : { a?: number | undefined; }
>a : number | undefined
}
g()
>g() : void

View file

@ -0,0 +1,27 @@
// @strict: true
interface Animal {
name: string;
kind: string;
age: number;
location: string;
owner: object;
}
function clonePet(pet: Animal, fullCopy?: boolean) {
return {
name: pet.name,
kind: pet.kind,
...(fullCopy && pet),
}
}
interface Animal2 {
name: string;
owner?: string;
}
function billOwner(pet: Animal2) {
return {
...(pet.owner && pet),
paid: false
}
}