From b9689228b5928b2524faf7f0e9ff5f5eba42a7b7 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 22 Nov 2019 17:19:17 -0800 Subject: [PATCH] =?UTF-8?q?When=20calculating=20spreads,=20merge=20empty?= =?UTF-8?q?=20object=20into=20nonempty=20object=20to=20=E2=80=A6=20(#34853?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * When calculating spreads, merge empty object into nonempty object to produce partial object to reduce complexity * Actually accept remainder of baselines * Limit simplification to single prop or partial types --- src/compiler/checker.ts | 63 +++ tests/baselines/reference/objectSpread.types | 26 +- .../objectSpreadIndexSignature.types | 4 +- .../objectSpreadRepeatedNullCheckPerf.js | 80 +++ .../objectSpreadRepeatedNullCheckPerf.symbols | 306 +++++++++++ .../objectSpreadRepeatedNullCheckPerf.types | 517 ++++++++++++++++++ ...ectLiteralAssignableToIndexSignature.types | 16 +- .../reference/spreadUnion2.errors.txt | 24 +- tests/baselines/reference/spreadUnion2.types | 12 +- tests/baselines/reference/spreadUnion3.types | 2 +- .../objectSpreadRepeatedNullCheckPerf.ts | 62 +++ 11 files changed, 1070 insertions(+), 42 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.js create mode 100644 tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.symbols create mode 100644 tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ae597684d04cf..6b64f6dfe7d1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12524,6 +12524,61 @@ namespace ts { return !!(type.flags & TypeFlags.Object) && !isGenericMappedType(type); } + function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) { + return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); + } + + function isSinglePropertyAnonymousObjectType(type: Type) { + return !!(type.flags & TypeFlags.Object) && + !!(getObjectFlags(type) & ObjectFlags.Anonymous) && + (length(getPropertiesOfType(type)) === 1 || every(getPropertiesOfType(type), p => !!(p.flags & SymbolFlags.Optional))); + } + + 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) && isSinglePropertyAnonymousObjectType(secondType)) { + return getAnonymousPartialType(secondType); + } + if (isEmptyObjectTypeOrSpreadsIntoEmptyObject(secondType) && isSinglePropertyAnonymousObjectType(firstType)) { + 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 + const members = createSymbolTable(); + for (const prop of getPropertiesOfType(type)) { + if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { + // do nothing, skip privates + } + else if (isSpreadableProperty(prop)) { + const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const flags = SymbolFlags.Property | SymbolFlags.Optional; + const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0); + result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); + result.declarations = prop.declarations; + result.nameType = prop.nameType; + result.syntheticOrigin = prop; + members.set(prop.escapedName, result); + } + } + const spread = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + getIndexInfoOfType(type, IndexKind.String), + getIndexInfoOfType(type, IndexKind.Number)); + spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + return spread; + } + } + /** * Since the source of spread types are object literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType @@ -12543,9 +12598,17 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { + const merged = tryMergeUnionOfObjectTypeAndEmptyObject(left as UnionType, readonly); + if (merged) { + return getSpreadType(merged, right, symbol, objectFlags, readonly); + } return mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly)); } if (right.flags & TypeFlags.Union) { + const merged = tryMergeUnionOfObjectTypeAndEmptyObject(right as UnionType, readonly); + if (merged) { + return getSpreadType(left, merged, symbol, objectFlags, readonly); + } return mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index aa083e5d9f1b0..2154a8ca75e71 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -244,7 +244,7 @@ function from16326(this: { header: Header }, header: Header, authToken: string): >authToken : string return { ->{ ...this.header, ...header, ...authToken && { authToken } } : { head: string; body: string; authToken: string; } | { authToken: string; head: string; body: string; } +>{ ...this.header, ...header, ...authToken && { authToken } } : { authToken: string; head: string; body: string; } ...this.header, >this.header : Header @@ -277,9 +277,9 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { >13 : 13 o = { ->o = { ...o, ...b && { x: 14 } } : { x: number; y: number; } | { x: number; y: number; } +>o = { ...o, ...b && { x: 14 } } : { x: number; y: number; } >o : { x: number; y: number; } ->{ ...o, ...b && { x: 14 } } : { x: number; y: number; } | { x: number; y: number; } +>{ ...o, ...b && { x: 14 } } : { x: number; y: number; } ...o, >o : { x: number; y: number; } @@ -292,8 +292,8 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { >14 : 14 } let o2 = { ...b && { x: 21 }} ->o2 : {} ->{ ...b && { x: 21 }} : { x: number; } | {} +>o2 : { x?: number; } +>{ ...b && { x: 21 }} : { x?: number; } >b && { x: 21 } : false | { x: number; } >b : boolean >{ x: 21 } : { x: number; } @@ -318,9 +318,9 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { >16 : 16 o = { ->o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } | { x: number; y: number; } +>o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } >o : { x: number; y: number; } ->{ ...o, ...nt && { x: nt } } : { x: number; y: number; } | { x: number; y: number; } +>{ ...o, ...nt && { x: nt } } : { x: number; y: number; } ...o, >o : { x: number; y: number; } @@ -333,8 +333,8 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { >nt : number } let o2 = { ...nt && { x: nt }} ->o2 : {} ->{ ...nt && { x: nt }} : { x: number; } | {} +>o2 : { x?: number; } +>{ ...nt && { x: nt }} : { x?: number; } >nt && { x: nt } : 0 | { x: number; } >nt : number >{ x: nt } : { x: number; } @@ -359,9 +359,9 @@ function conditionalSpreadString(st: string): { x: string, y: number } { >17 : 17 o = { ->o = { ...o, ...st && { x: st } } : { x: string; y: number; } | { x: string; y: number; } +>o = { ...o, ...st && { x: st } } : { x: string; y: number; } >o : { x: string; y: number; } ->{ ...o, ...st && { x: st } } : { x: string; y: number; } | { x: string; y: number; } +>{ ...o, ...st && { x: st } } : { x: string; y: number; } ...o, >o : { x: string; y: number; } @@ -374,8 +374,8 @@ function conditionalSpreadString(st: string): { x: string, y: number } { >st : string } let o2 = { ...st && { x: st }} ->o2 : {} ->{ ...st && { x: st }} : { x: string; } | {} +>o2 : { x?: string; } +>{ ...st && { x: st }} : { x?: string; } >st && { x: st } : "" | { x: string; } >st : string >{ x: st } : { x: string; } diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index 3ce4d00584ba9..5a057ded445bb 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -42,9 +42,9 @@ declare const b: boolean; >b : boolean indexed3 = { ...b ? indexed3 : undefined }; ->indexed3 = { ...b ? indexed3 : undefined } : {} | { [n: string]: number; } +>indexed3 = { ...b ? indexed3 : undefined } : { [n: string]: number; } >indexed3 : { [n: string]: number; } ->{ ...b ? indexed3 : undefined } : {} | { [n: string]: number; } +>{ ...b ? indexed3 : undefined } : { [n: string]: number; } >b ? indexed3 : undefined : { [n: string]: number; } | undefined >b : boolean >indexed3 : { [n: string]: number; } diff --git a/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.js b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.js new file mode 100644 index 0000000000000..b82c2bd8e189a --- /dev/null +++ b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.js @@ -0,0 +1,80 @@ +//// [objectSpreadRepeatedNullCheckPerf.ts] +interface Props { + readonly a?: string + readonly b?: string + readonly c?: string + readonly d?: string + readonly e?: string + readonly f?: string + readonly g?: string + readonly h?: string + readonly i?: string + readonly j?: string + readonly k?: string + readonly l?: string + readonly m?: string + readonly n?: string + readonly o?: string + readonly p?: string + readonly q?: string + readonly r?: string + readonly s?: string + readonly t?: string + readonly u?: string + readonly v?: string + readonly w?: string + readonly x?: string + readonly y?: string + readonly z?: string +} + +function parseWithSpread(config: Record): Props { + 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() } + } +} + +parseWithSpread({ a: 1, b: 2, z: 26 }) + +//// [objectSpreadRepeatedNullCheckPerf.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 parseWithSpread(config) { + return __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({}, 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() }); +} +parseWithSpread({ a: 1, b: 2, z: 26 }); diff --git a/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.symbols b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.symbols new file mode 100644 index 0000000000000..7683b145a8ad5 --- /dev/null +++ b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.symbols @@ -0,0 +1,306 @@ +=== tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts === +interface Props { +>Props : Symbol(Props, Decl(objectSpreadRepeatedNullCheckPerf.ts, 0, 0)) + + readonly a?: string +>a : Symbol(Props.a, Decl(objectSpreadRepeatedNullCheckPerf.ts, 0, 17)) + + readonly b?: string +>b : Symbol(Props.b, Decl(objectSpreadRepeatedNullCheckPerf.ts, 1, 23)) + + readonly c?: string +>c : Symbol(Props.c, Decl(objectSpreadRepeatedNullCheckPerf.ts, 2, 23)) + + readonly d?: string +>d : Symbol(Props.d, Decl(objectSpreadRepeatedNullCheckPerf.ts, 3, 23)) + + readonly e?: string +>e : Symbol(Props.e, Decl(objectSpreadRepeatedNullCheckPerf.ts, 4, 23)) + + readonly f?: string +>f : Symbol(Props.f, Decl(objectSpreadRepeatedNullCheckPerf.ts, 5, 23)) + + readonly g?: string +>g : Symbol(Props.g, Decl(objectSpreadRepeatedNullCheckPerf.ts, 6, 23)) + + readonly h?: string +>h : Symbol(Props.h, Decl(objectSpreadRepeatedNullCheckPerf.ts, 7, 23)) + + readonly i?: string +>i : Symbol(Props.i, Decl(objectSpreadRepeatedNullCheckPerf.ts, 8, 23)) + + readonly j?: string +>j : Symbol(Props.j, Decl(objectSpreadRepeatedNullCheckPerf.ts, 9, 23)) + + readonly k?: string +>k : Symbol(Props.k, Decl(objectSpreadRepeatedNullCheckPerf.ts, 10, 23)) + + readonly l?: string +>l : Symbol(Props.l, Decl(objectSpreadRepeatedNullCheckPerf.ts, 11, 23)) + + readonly m?: string +>m : Symbol(Props.m, Decl(objectSpreadRepeatedNullCheckPerf.ts, 12, 23)) + + readonly n?: string +>n : Symbol(Props.n, Decl(objectSpreadRepeatedNullCheckPerf.ts, 13, 23)) + + readonly o?: string +>o : Symbol(Props.o, Decl(objectSpreadRepeatedNullCheckPerf.ts, 14, 23)) + + readonly p?: string +>p : Symbol(Props.p, Decl(objectSpreadRepeatedNullCheckPerf.ts, 15, 23)) + + readonly q?: string +>q : Symbol(Props.q, Decl(objectSpreadRepeatedNullCheckPerf.ts, 16, 23)) + + readonly r?: string +>r : Symbol(Props.r, Decl(objectSpreadRepeatedNullCheckPerf.ts, 17, 23)) + + readonly s?: string +>s : Symbol(Props.s, Decl(objectSpreadRepeatedNullCheckPerf.ts, 18, 23)) + + readonly t?: string +>t : Symbol(Props.t, Decl(objectSpreadRepeatedNullCheckPerf.ts, 19, 23)) + + readonly u?: string +>u : Symbol(Props.u, Decl(objectSpreadRepeatedNullCheckPerf.ts, 20, 23)) + + readonly v?: string +>v : Symbol(Props.v, Decl(objectSpreadRepeatedNullCheckPerf.ts, 21, 23)) + + readonly w?: string +>w : Symbol(Props.w, Decl(objectSpreadRepeatedNullCheckPerf.ts, 22, 23)) + + readonly x?: string +>x : Symbol(Props.x, Decl(objectSpreadRepeatedNullCheckPerf.ts, 23, 23)) + + readonly y?: string +>y : Symbol(Props.y, Decl(objectSpreadRepeatedNullCheckPerf.ts, 24, 23)) + + readonly z?: string +>z : Symbol(Props.z, Decl(objectSpreadRepeatedNullCheckPerf.ts, 25, 23)) +} + +function parseWithSpread(config: Record): Props { +>parseWithSpread : Symbol(parseWithSpread, Decl(objectSpreadRepeatedNullCheckPerf.ts, 27, 1)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>Props : Symbol(Props, Decl(objectSpreadRepeatedNullCheckPerf.ts, 0, 0)) + + return { + ...config.a !== undefined && { a: config.a.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>a : Symbol(a, Decl(objectSpreadRepeatedNullCheckPerf.ts, 31, 38)) +>config.a.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.b !== undefined && { b: config.b.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>b : Symbol(b, Decl(objectSpreadRepeatedNullCheckPerf.ts, 32, 38)) +>config.b.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.c !== undefined && { c: config.c.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>c : Symbol(c, Decl(objectSpreadRepeatedNullCheckPerf.ts, 33, 38)) +>config.c.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.d !== undefined && { d: config.d.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>d : Symbol(d, Decl(objectSpreadRepeatedNullCheckPerf.ts, 34, 38)) +>config.d.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.e !== undefined && { e: config.e.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>e : Symbol(e, Decl(objectSpreadRepeatedNullCheckPerf.ts, 35, 38)) +>config.e.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.f !== undefined && { f: config.f.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>f : Symbol(f, Decl(objectSpreadRepeatedNullCheckPerf.ts, 36, 38)) +>config.f.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.g !== undefined && { g: config.g.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>g : Symbol(g, Decl(objectSpreadRepeatedNullCheckPerf.ts, 37, 38)) +>config.g.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.h !== undefined && { h: config.h.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>h : Symbol(h, Decl(objectSpreadRepeatedNullCheckPerf.ts, 38, 38)) +>config.h.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.i !== undefined && { i: config.i.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>i : Symbol(i, Decl(objectSpreadRepeatedNullCheckPerf.ts, 39, 38)) +>config.i.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.j !== undefined && { j: config.j.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>j : Symbol(j, Decl(objectSpreadRepeatedNullCheckPerf.ts, 40, 38)) +>config.j.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.k !== undefined && { k: config.k.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>k : Symbol(k, Decl(objectSpreadRepeatedNullCheckPerf.ts, 41, 38)) +>config.k.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.l !== undefined && { l: config.l.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>l : Symbol(l, Decl(objectSpreadRepeatedNullCheckPerf.ts, 42, 38)) +>config.l.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.m !== undefined && { m: config.m.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>m : Symbol(m, Decl(objectSpreadRepeatedNullCheckPerf.ts, 43, 38)) +>config.m.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.n !== undefined && { n: config.n.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>n : Symbol(n, Decl(objectSpreadRepeatedNullCheckPerf.ts, 44, 38)) +>config.n.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.o !== undefined && { o: config.o.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>o : Symbol(o, Decl(objectSpreadRepeatedNullCheckPerf.ts, 45, 38)) +>config.o.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.p !== undefined && { p: config.p.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>p : Symbol(p, Decl(objectSpreadRepeatedNullCheckPerf.ts, 46, 38)) +>config.p.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.q !== undefined && { q: config.q.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>q : Symbol(q, Decl(objectSpreadRepeatedNullCheckPerf.ts, 47, 38)) +>config.q.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.r !== undefined && { r: config.r.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>r : Symbol(r, Decl(objectSpreadRepeatedNullCheckPerf.ts, 48, 38)) +>config.r.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.s !== undefined && { s: config.s.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>s : Symbol(s, Decl(objectSpreadRepeatedNullCheckPerf.ts, 49, 38)) +>config.s.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.t !== undefined && { t: config.t.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>t : Symbol(t, Decl(objectSpreadRepeatedNullCheckPerf.ts, 50, 38)) +>config.t.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.u !== undefined && { u: config.u.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>u : Symbol(u, Decl(objectSpreadRepeatedNullCheckPerf.ts, 51, 38)) +>config.u.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.v !== undefined && { v: config.v.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>v : Symbol(v, Decl(objectSpreadRepeatedNullCheckPerf.ts, 52, 38)) +>config.v.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.w !== undefined && { w: config.w.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>w : Symbol(w, Decl(objectSpreadRepeatedNullCheckPerf.ts, 53, 38)) +>config.w.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.x !== undefined && { x: config.x.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(objectSpreadRepeatedNullCheckPerf.ts, 54, 38)) +>config.x.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.y !== undefined && { y: config.y.toString() }, +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>y : Symbol(y, Decl(objectSpreadRepeatedNullCheckPerf.ts, 55, 38)) +>config.y.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + ...config.z !== undefined && { z: config.z.toString() } +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>undefined : Symbol(undefined) +>z : Symbol(z, Decl(objectSpreadRepeatedNullCheckPerf.ts, 56, 38)) +>config.z.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>config : Symbol(config, Decl(objectSpreadRepeatedNullCheckPerf.ts, 29, 25)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + +parseWithSpread({ a: 1, b: 2, z: 26 }) +>parseWithSpread : Symbol(parseWithSpread, Decl(objectSpreadRepeatedNullCheckPerf.ts, 27, 1)) +>a : Symbol(a, Decl(objectSpreadRepeatedNullCheckPerf.ts, 60, 17)) +>b : Symbol(b, Decl(objectSpreadRepeatedNullCheckPerf.ts, 60, 23)) +>z : Symbol(z, Decl(objectSpreadRepeatedNullCheckPerf.ts, 60, 29)) + diff --git a/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.types b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.types new file mode 100644 index 0000000000000..d2f1e79037175 --- /dev/null +++ b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.types @@ -0,0 +1,517 @@ +=== tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts === +interface Props { + readonly a?: string +>a : string | undefined + + readonly b?: string +>b : string | undefined + + readonly c?: string +>c : string | undefined + + readonly d?: string +>d : string | undefined + + readonly e?: string +>e : string | undefined + + readonly f?: string +>f : string | undefined + + readonly g?: string +>g : string | undefined + + readonly h?: string +>h : string | undefined + + readonly i?: string +>i : string | undefined + + readonly j?: string +>j : string | undefined + + readonly k?: string +>k : string | undefined + + readonly l?: string +>l : string | undefined + + readonly m?: string +>m : string | undefined + + readonly n?: string +>n : string | undefined + + readonly o?: string +>o : string | undefined + + readonly p?: string +>p : string | undefined + + readonly q?: string +>q : string | undefined + + readonly r?: string +>r : string | undefined + + readonly s?: string +>s : string | undefined + + readonly t?: string +>t : string | undefined + + readonly u?: string +>u : string | undefined + + readonly v?: string +>v : string | undefined + + readonly w?: string +>w : string | undefined + + readonly x?: string +>x : string | undefined + + readonly y?: string +>y : string | undefined + + readonly z?: string +>z : string | undefined +} + +function parseWithSpread(config: Record): Props { +>parseWithSpread : (config: Record) => Props +>config : Record + + 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.a !== undefined && { a: config.a.toString() } : false | { a: string; } +>config.a !== undefined : boolean +>config.a : number +>config : Record +>a : number +>undefined : undefined +>{ a: config.a.toString() } : { a: string; } +>a : string +>config.a.toString() : string +>config.a.toString : (radix?: number | undefined) => string +>config.a : number +>config : Record +>a : number +>toString : (radix?: number | undefined) => string + + ...config.b !== undefined && { b: config.b.toString() }, +>config.b !== undefined && { b: config.b.toString() } : false | { b: string; } +>config.b !== undefined : boolean +>config.b : number +>config : Record +>b : number +>undefined : undefined +>{ b: config.b.toString() } : { b: string; } +>b : string +>config.b.toString() : string +>config.b.toString : (radix?: number | undefined) => string +>config.b : number +>config : Record +>b : number +>toString : (radix?: number | undefined) => string + + ...config.c !== undefined && { c: config.c.toString() }, +>config.c !== undefined && { c: config.c.toString() } : false | { c: string; } +>config.c !== undefined : boolean +>config.c : number +>config : Record +>c : number +>undefined : undefined +>{ c: config.c.toString() } : { c: string; } +>c : string +>config.c.toString() : string +>config.c.toString : (radix?: number | undefined) => string +>config.c : number +>config : Record +>c : number +>toString : (radix?: number | undefined) => string + + ...config.d !== undefined && { d: config.d.toString() }, +>config.d !== undefined && { d: config.d.toString() } : false | { d: string; } +>config.d !== undefined : boolean +>config.d : number +>config : Record +>d : number +>undefined : undefined +>{ d: config.d.toString() } : { d: string; } +>d : string +>config.d.toString() : string +>config.d.toString : (radix?: number | undefined) => string +>config.d : number +>config : Record +>d : number +>toString : (radix?: number | undefined) => string + + ...config.e !== undefined && { e: config.e.toString() }, +>config.e !== undefined && { e: config.e.toString() } : false | { e: string; } +>config.e !== undefined : boolean +>config.e : number +>config : Record +>e : number +>undefined : undefined +>{ e: config.e.toString() } : { e: string; } +>e : string +>config.e.toString() : string +>config.e.toString : (radix?: number | undefined) => string +>config.e : number +>config : Record +>e : number +>toString : (radix?: number | undefined) => string + + ...config.f !== undefined && { f: config.f.toString() }, +>config.f !== undefined && { f: config.f.toString() } : false | { f: string; } +>config.f !== undefined : boolean +>config.f : number +>config : Record +>f : number +>undefined : undefined +>{ f: config.f.toString() } : { f: string; } +>f : string +>config.f.toString() : string +>config.f.toString : (radix?: number | undefined) => string +>config.f : number +>config : Record +>f : number +>toString : (radix?: number | undefined) => string + + ...config.g !== undefined && { g: config.g.toString() }, +>config.g !== undefined && { g: config.g.toString() } : false | { g: string; } +>config.g !== undefined : boolean +>config.g : number +>config : Record +>g : number +>undefined : undefined +>{ g: config.g.toString() } : { g: string; } +>g : string +>config.g.toString() : string +>config.g.toString : (radix?: number | undefined) => string +>config.g : number +>config : Record +>g : number +>toString : (radix?: number | undefined) => string + + ...config.h !== undefined && { h: config.h.toString() }, +>config.h !== undefined && { h: config.h.toString() } : false | { h: string; } +>config.h !== undefined : boolean +>config.h : number +>config : Record +>h : number +>undefined : undefined +>{ h: config.h.toString() } : { h: string; } +>h : string +>config.h.toString() : string +>config.h.toString : (radix?: number | undefined) => string +>config.h : number +>config : Record +>h : number +>toString : (radix?: number | undefined) => string + + ...config.i !== undefined && { i: config.i.toString() }, +>config.i !== undefined && { i: config.i.toString() } : false | { i: string; } +>config.i !== undefined : boolean +>config.i : number +>config : Record +>i : number +>undefined : undefined +>{ i: config.i.toString() } : { i: string; } +>i : string +>config.i.toString() : string +>config.i.toString : (radix?: number | undefined) => string +>config.i : number +>config : Record +>i : number +>toString : (radix?: number | undefined) => string + + ...config.j !== undefined && { j: config.j.toString() }, +>config.j !== undefined && { j: config.j.toString() } : false | { j: string; } +>config.j !== undefined : boolean +>config.j : number +>config : Record +>j : number +>undefined : undefined +>{ j: config.j.toString() } : { j: string; } +>j : string +>config.j.toString() : string +>config.j.toString : (radix?: number | undefined) => string +>config.j : number +>config : Record +>j : number +>toString : (radix?: number | undefined) => string + + ...config.k !== undefined && { k: config.k.toString() }, +>config.k !== undefined && { k: config.k.toString() } : false | { k: string; } +>config.k !== undefined : boolean +>config.k : number +>config : Record +>k : number +>undefined : undefined +>{ k: config.k.toString() } : { k: string; } +>k : string +>config.k.toString() : string +>config.k.toString : (radix?: number | undefined) => string +>config.k : number +>config : Record +>k : number +>toString : (radix?: number | undefined) => string + + ...config.l !== undefined && { l: config.l.toString() }, +>config.l !== undefined && { l: config.l.toString() } : false | { l: string; } +>config.l !== undefined : boolean +>config.l : number +>config : Record +>l : number +>undefined : undefined +>{ l: config.l.toString() } : { l: string; } +>l : string +>config.l.toString() : string +>config.l.toString : (radix?: number | undefined) => string +>config.l : number +>config : Record +>l : number +>toString : (radix?: number | undefined) => string + + ...config.m !== undefined && { m: config.m.toString() }, +>config.m !== undefined && { m: config.m.toString() } : false | { m: string; } +>config.m !== undefined : boolean +>config.m : number +>config : Record +>m : number +>undefined : undefined +>{ m: config.m.toString() } : { m: string; } +>m : string +>config.m.toString() : string +>config.m.toString : (radix?: number | undefined) => string +>config.m : number +>config : Record +>m : number +>toString : (radix?: number | undefined) => string + + ...config.n !== undefined && { n: config.n.toString() }, +>config.n !== undefined && { n: config.n.toString() } : false | { n: string; } +>config.n !== undefined : boolean +>config.n : number +>config : Record +>n : number +>undefined : undefined +>{ n: config.n.toString() } : { n: string; } +>n : string +>config.n.toString() : string +>config.n.toString : (radix?: number | undefined) => string +>config.n : number +>config : Record +>n : number +>toString : (radix?: number | undefined) => string + + ...config.o !== undefined && { o: config.o.toString() }, +>config.o !== undefined && { o: config.o.toString() } : false | { o: string; } +>config.o !== undefined : boolean +>config.o : number +>config : Record +>o : number +>undefined : undefined +>{ o: config.o.toString() } : { o: string; } +>o : string +>config.o.toString() : string +>config.o.toString : (radix?: number | undefined) => string +>config.o : number +>config : Record +>o : number +>toString : (radix?: number | undefined) => string + + ...config.p !== undefined && { p: config.p.toString() }, +>config.p !== undefined && { p: config.p.toString() } : false | { p: string; } +>config.p !== undefined : boolean +>config.p : number +>config : Record +>p : number +>undefined : undefined +>{ p: config.p.toString() } : { p: string; } +>p : string +>config.p.toString() : string +>config.p.toString : (radix?: number | undefined) => string +>config.p : number +>config : Record +>p : number +>toString : (radix?: number | undefined) => string + + ...config.q !== undefined && { q: config.q.toString() }, +>config.q !== undefined && { q: config.q.toString() } : false | { q: string; } +>config.q !== undefined : boolean +>config.q : number +>config : Record +>q : number +>undefined : undefined +>{ q: config.q.toString() } : { q: string; } +>q : string +>config.q.toString() : string +>config.q.toString : (radix?: number | undefined) => string +>config.q : number +>config : Record +>q : number +>toString : (radix?: number | undefined) => string + + ...config.r !== undefined && { r: config.r.toString() }, +>config.r !== undefined && { r: config.r.toString() } : false | { r: string; } +>config.r !== undefined : boolean +>config.r : number +>config : Record +>r : number +>undefined : undefined +>{ r: config.r.toString() } : { r: string; } +>r : string +>config.r.toString() : string +>config.r.toString : (radix?: number | undefined) => string +>config.r : number +>config : Record +>r : number +>toString : (radix?: number | undefined) => string + + ...config.s !== undefined && { s: config.s.toString() }, +>config.s !== undefined && { s: config.s.toString() } : false | { s: string; } +>config.s !== undefined : boolean +>config.s : number +>config : Record +>s : number +>undefined : undefined +>{ s: config.s.toString() } : { s: string; } +>s : string +>config.s.toString() : string +>config.s.toString : (radix?: number | undefined) => string +>config.s : number +>config : Record +>s : number +>toString : (radix?: number | undefined) => string + + ...config.t !== undefined && { t: config.t.toString() }, +>config.t !== undefined && { t: config.t.toString() } : false | { t: string; } +>config.t !== undefined : boolean +>config.t : number +>config : Record +>t : number +>undefined : undefined +>{ t: config.t.toString() } : { t: string; } +>t : string +>config.t.toString() : string +>config.t.toString : (radix?: number | undefined) => string +>config.t : number +>config : Record +>t : number +>toString : (radix?: number | undefined) => string + + ...config.u !== undefined && { u: config.u.toString() }, +>config.u !== undefined && { u: config.u.toString() } : false | { u: string; } +>config.u !== undefined : boolean +>config.u : number +>config : Record +>u : number +>undefined : undefined +>{ u: config.u.toString() } : { u: string; } +>u : string +>config.u.toString() : string +>config.u.toString : (radix?: number | undefined) => string +>config.u : number +>config : Record +>u : number +>toString : (radix?: number | undefined) => string + + ...config.v !== undefined && { v: config.v.toString() }, +>config.v !== undefined && { v: config.v.toString() } : false | { v: string; } +>config.v !== undefined : boolean +>config.v : number +>config : Record +>v : number +>undefined : undefined +>{ v: config.v.toString() } : { v: string; } +>v : string +>config.v.toString() : string +>config.v.toString : (radix?: number | undefined) => string +>config.v : number +>config : Record +>v : number +>toString : (radix?: number | undefined) => string + + ...config.w !== undefined && { w: config.w.toString() }, +>config.w !== undefined && { w: config.w.toString() } : false | { w: string; } +>config.w !== undefined : boolean +>config.w : number +>config : Record +>w : number +>undefined : undefined +>{ w: config.w.toString() } : { w: string; } +>w : string +>config.w.toString() : string +>config.w.toString : (radix?: number | undefined) => string +>config.w : number +>config : Record +>w : number +>toString : (radix?: number | undefined) => string + + ...config.x !== undefined && { x: config.x.toString() }, +>config.x !== undefined && { x: config.x.toString() } : false | { x: string; } +>config.x !== undefined : boolean +>config.x : number +>config : Record +>x : number +>undefined : undefined +>{ x: config.x.toString() } : { x: string; } +>x : string +>config.x.toString() : string +>config.x.toString : (radix?: number | undefined) => string +>config.x : number +>config : Record +>x : number +>toString : (radix?: number | undefined) => string + + ...config.y !== undefined && { y: config.y.toString() }, +>config.y !== undefined && { y: config.y.toString() } : false | { y: string; } +>config.y !== undefined : boolean +>config.y : number +>config : Record +>y : number +>undefined : undefined +>{ y: config.y.toString() } : { y: string; } +>y : string +>config.y.toString() : string +>config.y.toString : (radix?: number | undefined) => string +>config.y : number +>config : Record +>y : number +>toString : (radix?: number | undefined) => string + + ...config.z !== undefined && { z: config.z.toString() } +>config.z !== undefined && { z: config.z.toString() } : false | { z: string; } +>config.z !== undefined : boolean +>config.z : number +>config : Record +>z : number +>undefined : undefined +>{ z: config.z.toString() } : { z: string; } +>z : string +>config.z.toString() : string +>config.z.toString : (radix?: number | undefined) => string +>config.z : number +>config : Record +>z : number +>toString : (radix?: number | undefined) => string + } +} + +parseWithSpread({ a: 1, b: 2, z: 26 }) +>parseWithSpread({ a: 1, b: 2, z: 26 }) : Props +>parseWithSpread : (config: Record) => Props +>{ a: 1, b: 2, z: 26 } : { a: number; b: number; z: number; } +>a : number +>1 : 1 +>b : number +>2 : 2 +>z : number +>26 : 26 + diff --git a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types index 672170acbcd8e..53462c68c03ea 100644 --- a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types +++ b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.types @@ -9,11 +9,11 @@ const recordOfRecords: RecordOfRecords = {} >{} : {} recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK ->recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>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 ? {foo} : {} : { foo: Record; } | {} >foo !== undefined : boolean @@ -36,11 +36,11 @@ recordOfRecords.propB = {...(foo && {foo})} // OK >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 = {...(foo !== undefined && {foo})} : { foo?: Record; } >recordOfRecords.propC : RecordOfRecords >recordOfRecords : RecordOfRecords >propC : RecordOfRecords ->{...(foo !== undefined && {foo})} : { foo: Record; } | {} +>{...(foo !== undefined && {foo})} : { foo?: Record; } >(foo !== undefined && {foo}) : false | { foo: Record; } >foo !== undefined && {foo} : false | { foo: Record; } >foo !== undefined : boolean @@ -55,11 +55,11 @@ const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} >{} : {} recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK ->recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} : { foo: Record; } | {} +>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 ? {foo} : {} : { foo: Record; } | {} >foo !== undefined : boolean @@ -82,11 +82,11 @@ recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK >foo : Record recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK ->recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo: Record; } | {} +>recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} : { foo?: Record; } >recordsOfRecordsOrEmpty.propC : {} | RecordOfRecordsOrEmpty >recordsOfRecordsOrEmpty : RecordOfRecordsOrEmpty >propC : {} | RecordOfRecordsOrEmpty ->{...(foo !== undefined && {foo})} : { foo: Record; } | {} +>{...(foo !== undefined && {foo})} : { foo?: Record; } >(foo !== undefined && {foo}) : false | { foo: Record; } >foo !== undefined && {foo} : false | { foo: Record; } >foo !== undefined : boolean diff --git a/tests/baselines/reference/spreadUnion2.errors.txt b/tests/baselines/reference/spreadUnion2.errors.txt index f2c1bc757783e..104998996a766 100644 --- a/tests/baselines/reference/spreadUnion2.errors.txt +++ b/tests/baselines/reference/spreadUnion2.errors.txt @@ -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 '{}'. -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 '{}'. -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 '{}'. -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 '{}'. -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 '{}'. -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 '{}'. +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 (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 '{}'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'. !!! 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 '{}'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'. !!! 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 '{}'. +!!! 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; }'. !!! 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 '{}'. +!!! 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; }'. !!! 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 '{}'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' must be of type '{} | { a: number; }', but here has type '{ a?: number; }'. !!! 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 '{}'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' must be of type '{} | { b: number; }', but here has type '{ b?: number; }'. !!! related TS6203 tests/cases/conformance/types/spread/spreadUnion2.ts:17:5: 'o5' was also declared here. \ No newline at end of file diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types index 5077949bc9724..bbb1a50eec6e3 100644 --- a/tests/baselines/reference/spreadUnion2.types +++ b/tests/baselines/reference/spreadUnion2.types @@ -14,7 +14,7 @@ var o1: {} | { a: number }; var o1 = { ...undefinedUnion }; >o1 : {} | { a: number; } ->{ ...undefinedUnion } : {} | { a: number; } +>{ ...undefinedUnion } : { a?: number; } >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; } >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; } | { b: number; a: number; } +>{ ...undefinedUnion, ...nullUnion } : { b?: number; a?: number; } >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; } | { a: number; b: number; } +>{ ...nullUnion, ...undefinedUnion } : { a?: number; b?: number; } >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; } | { a: number; } | { a: number; } +>{ ...undefinedUnion, ...undefinedUnion } : { a?: number; } >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; } | { b: number; } | { b: number; } +>{ ...nullUnion, ...nullUnion } : { b?: number; } >nullUnion : { b: number; } | null >nullUnion : { b: number; } | null diff --git a/tests/baselines/reference/spreadUnion3.types b/tests/baselines/reference/spreadUnion3.types index 940ec96f5b7c3..9ea23212844f5 100644 --- a/tests/baselines/reference/spreadUnion3.types +++ b/tests/baselines/reference/spreadUnion3.types @@ -6,7 +6,7 @@ function f(x: { y: string } | undefined): { y: string } { >y : string return { y: 123, ...x } // y: string | number ->{ y: 123, ...x } : { y: number; } | { y: string; } +>{ y: 123, ...x } : { y: string | number; } >y : number >123 : 123 >x : { y: string; } | undefined diff --git a/tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts b/tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts new file mode 100644 index 0000000000000..aa4877b20c361 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadRepeatedNullCheckPerf.ts @@ -0,0 +1,62 @@ +// @strict: true +interface Props { + readonly a?: string + readonly b?: string + readonly c?: string + readonly d?: string + readonly e?: string + readonly f?: string + readonly g?: string + readonly h?: string + readonly i?: string + readonly j?: string + readonly k?: string + readonly l?: string + readonly m?: string + readonly n?: string + readonly o?: string + readonly p?: string + readonly q?: string + readonly r?: string + readonly s?: string + readonly t?: string + readonly u?: string + readonly v?: string + readonly w?: string + readonly x?: string + readonly y?: string + readonly z?: string +} + +function parseWithSpread(config: Record): Props { + 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() } + } +} + +parseWithSpread({ a: 1, b: 2, z: 26 }) \ No newline at end of file