Merge pull request #40755 from amcasey/SpreadLimit

Enforce a size limit in getSpreadType
This commit is contained in:
Andrew Casey 2020-09-30 13:44:59 -07:00 committed by GitHub
commit 35111231f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 964 additions and 2 deletions

View file

@ -13404,6 +13404,7 @@ namespace ts {
function checkCrossProductUnion(types: readonly Type[]) {
const size = reduceLeft(types, (n, t) => n * (t.flags & TypeFlags.Union ? (<UnionType>t).types.length : t.flags & TypeFlags.Never ? 0 : 1), 1);
if (size >= 100000) {
tracing.instant(tracing.Phase.Check, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size });
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
return false;
}
@ -14468,14 +14469,18 @@ namespace ts {
if (merged) {
return getSpreadType(merged, right, symbol, objectFlags, readonly);
}
return mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly));
return checkCrossProductUnion([left, right])
? mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly))
: errorType;
}
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));
return checkCrossProductUnion([left, right])
? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly))
: errorType;
}
if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) {
return left;

View file

@ -0,0 +1,170 @@
tests/cases/conformance/types/spread/objectSpreadRepeatedComplexity.ts(3,12): error TS2590: Expression produces a union type that is too complex to represent.
==== tests/cases/conformance/types/spread/objectSpreadRepeatedComplexity.ts (1 errors) ====
function f(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,
~~~~~~~~~~~~~~~~~~~~~~~
}),
~~~~~~~~~~~
};
~~~~~
!!! error TS2590: Expression produces a union type that is too complex to represent.
}

View file

@ -0,0 +1,160 @@
//// [objectSpreadRepeatedComplexity.ts]
function f(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,
}),
};
}
//// [objectSpreadRepeatedComplexity.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 f(cnd) {
// Type is a union of 2^(n-1) members, where n is the number of spread objects
return __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({}, (cnd[1] &&
cnd[2] && {
prop0: 0
})), (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
}));
}

View file

@ -0,0 +1,203 @@
=== tests/cases/conformance/types/spread/objectSpreadRepeatedComplexity.ts ===
function f(cnd: Record<number, boolean>){
>f : Symbol(f, Decl(objectSpreadRepeatedComplexity.ts, 0, 0))
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
// 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 : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
cnd[2] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop0: 0,
>prop0 : Symbol(prop0, Decl(objectSpreadRepeatedComplexity.ts, 5, 23))
}),
// With one prop each, it collapses to a single object (#34853?)
...(cnd[3] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop3a: 1,
>prop3a : Symbol(prop3a, Decl(objectSpreadRepeatedComplexity.ts, 10, 23))
prop3b: 1,
>prop3b : Symbol(prop3b, Decl(objectSpreadRepeatedComplexity.ts, 11, 22))
}),
...(cnd[4] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop4a: 1,
>prop4a : Symbol(prop4a, Decl(objectSpreadRepeatedComplexity.ts, 14, 23))
prop4b: 1,
>prop4b : Symbol(prop4b, Decl(objectSpreadRepeatedComplexity.ts, 15, 22))
}),
...(cnd[5] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop5a: 1,
>prop5a : Symbol(prop5a, Decl(objectSpreadRepeatedComplexity.ts, 18, 23))
prop5b: 1,
>prop5b : Symbol(prop5b, Decl(objectSpreadRepeatedComplexity.ts, 19, 22))
}),
...(cnd[6] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop6a: 1,
>prop6a : Symbol(prop6a, Decl(objectSpreadRepeatedComplexity.ts, 22, 23))
prop6b: 1,
>prop6b : Symbol(prop6b, Decl(objectSpreadRepeatedComplexity.ts, 23, 22))
}),
...(cnd[7] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop7a: 1,
>prop7a : Symbol(prop7a, Decl(objectSpreadRepeatedComplexity.ts, 26, 23))
prop7b: 1,
>prop7b : Symbol(prop7b, Decl(objectSpreadRepeatedComplexity.ts, 27, 22))
}),
...(cnd[8] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop8a: 1,
>prop8a : Symbol(prop8a, Decl(objectSpreadRepeatedComplexity.ts, 30, 23))
prop8b: 1,
>prop8b : Symbol(prop8b, Decl(objectSpreadRepeatedComplexity.ts, 31, 22))
}),
...(cnd[9] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop9a: 1,
>prop9a : Symbol(prop9a, Decl(objectSpreadRepeatedComplexity.ts, 34, 23))
prop9b: 1,
>prop9b : Symbol(prop9b, Decl(objectSpreadRepeatedComplexity.ts, 35, 22))
}),
...(cnd[10] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop10a: 1,
>prop10a : Symbol(prop10a, Decl(objectSpreadRepeatedComplexity.ts, 38, 24))
prop10b: 1,
>prop10b : Symbol(prop10b, Decl(objectSpreadRepeatedComplexity.ts, 39, 23))
}),
...(cnd[11] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop11a: 1,
>prop11a : Symbol(prop11a, Decl(objectSpreadRepeatedComplexity.ts, 42, 24))
prop11b: 1,
>prop11b : Symbol(prop11b, Decl(objectSpreadRepeatedComplexity.ts, 43, 23))
}),
...(cnd[12] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop12a: 1,
>prop12a : Symbol(prop12a, Decl(objectSpreadRepeatedComplexity.ts, 46, 24))
prop12b: 1,
>prop12b : Symbol(prop12b, Decl(objectSpreadRepeatedComplexity.ts, 47, 23))
}),
...(cnd[13] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop13a: 1,
>prop13a : Symbol(prop13a, Decl(objectSpreadRepeatedComplexity.ts, 50, 24))
prop13b: 1,
>prop13b : Symbol(prop13b, Decl(objectSpreadRepeatedComplexity.ts, 51, 23))
}),
...(cnd[14] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop14a: 1,
>prop14a : Symbol(prop14a, Decl(objectSpreadRepeatedComplexity.ts, 54, 24))
prop14b: 1,
>prop14b : Symbol(prop14b, Decl(objectSpreadRepeatedComplexity.ts, 55, 23))
}),
...(cnd[15] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop15a: 1,
>prop15a : Symbol(prop15a, Decl(objectSpreadRepeatedComplexity.ts, 58, 24))
prop15b: 1,
>prop15b : Symbol(prop15b, Decl(objectSpreadRepeatedComplexity.ts, 59, 23))
}),
...(cnd[16] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop16a: 1,
>prop16a : Symbol(prop16a, Decl(objectSpreadRepeatedComplexity.ts, 62, 24))
prop16b: 1,
>prop16b : Symbol(prop16b, Decl(objectSpreadRepeatedComplexity.ts, 63, 23))
}),
...(cnd[17] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop17a: 1,
>prop17a : Symbol(prop17a, Decl(objectSpreadRepeatedComplexity.ts, 66, 24))
prop17b: 1,
>prop17b : Symbol(prop17b, Decl(objectSpreadRepeatedComplexity.ts, 67, 23))
}),
...(cnd[18] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop18a: 1,
>prop18a : Symbol(prop18a, Decl(objectSpreadRepeatedComplexity.ts, 70, 24))
prop18b: 1,
>prop18b : Symbol(prop18b, Decl(objectSpreadRepeatedComplexity.ts, 71, 23))
}),
...(cnd[19] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop19a: 1,
>prop19a : Symbol(prop19a, Decl(objectSpreadRepeatedComplexity.ts, 74, 24))
prop19b: 1,
>prop19b : Symbol(prop19b, Decl(objectSpreadRepeatedComplexity.ts, 75, 23))
}),
...(cnd[20] && {
>cnd : Symbol(cnd, Decl(objectSpreadRepeatedComplexity.ts, 0, 11))
prop20a: 1,
>prop20a : Symbol(prop20a, Decl(objectSpreadRepeatedComplexity.ts, 78, 24))
prop20b: 1,
>prop20b : Symbol(prop20b, Decl(objectSpreadRepeatedComplexity.ts, 79, 23))
}),
};
}

View file

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

View file

@ -0,0 +1,85 @@
// @strict: true
function f(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,
}),
};
}