diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d044fa5bf0f4..f189189416f5c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16306,6 +16306,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } + function getTupleElementTypes(type: Type, seenTypes = new Set()): readonly Type[] { + // Guard against circular references using a Set + if (seenTypes.has(type)) { + return emptyArray; + } + + // Add the current type to the Set to track it + seenTypes.add(type); + + if (isTupleType(type)) { + const target = type.target; + if (target?.resolvedTypeArguments) { + return target.resolvedTypeArguments; + } + + if (type.objectFlags & ObjectFlags.Tuple) { + const tupleTarget = type as unknown as TupleType; + if (tupleTarget.elementFlags) { + return getTypeArguments(type) || emptyArray; + } + } + } + return emptyArray; + } + function getTypeArguments(type: TypeReference): readonly Type[] { if (!type.resolvedTypeArguments) { if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedTypeArguments)) { @@ -18154,13 +18179,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return reduceLeft(types, (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, 1); } - function checkCrossProductUnion(types: readonly Type[]) { + function containsDeeplyNestedType(types: readonly Type[], maxDepth: number, currentDepth: number = 0): boolean { + if (currentDepth >= maxDepth) return true; + + for (const type of types) { + // Check if the type is a union type + if (isUnionType(type)) { + if (containsDeeplyNestedType(type.types, maxDepth, currentDepth + 1)) { + return true; + } + } + + // Check if the type is a tuple type + if (isTupleType(type)) { + const tupleElementTypes = getTupleElementTypes(type); + if (containsDeeplyNestedType(tupleElementTypes, maxDepth, currentDepth + 1)) { + return true; + } + } + } + + return false; + } + + function checkCrossProductUnion(types: readonly Type[]): boolean { const size = getCrossProductUnionSize(types); + + // Check if the cross-product size exceeds the threshold if (size >= 100000) { - tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size }); + tracing?.instant(tracing.Phase.CheckTypes, "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; + } + + // Check for excessive nesting within types + const maxDepth = 3; + if (containsDeeplyNestedType(types, maxDepth)) { + tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_TooNested", { + typeIds: types.map(t => t.id), + }); error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); return false; } + return true; } @@ -25039,6 +25103,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); } + /** + * Determines if the given type is a union type. + * + * A union type is a type formed by combining multiple types + * using the `|` operator (e.g., `string | number`). This function + * checks if the provided type has the `TypeFlags.Union` flag set. + * + * @param type - The `Type` instance to check. + * @returns `true` if the type is a union type, otherwise `false`. + */ + function isUnionType(type: Type): type is UnionType { + return (type.flags & TypeFlags.Union) !== 0; + } + function isGenericTupleType(type: Type): type is TupleTypeReference { return isTupleType(type) && !!(type.target.combinedFlags & ElementFlags.Variadic); } diff --git a/tests/baselines/reference/tupleComplexity.errors.txt b/tests/baselines/reference/tupleComplexity.errors.txt new file mode 100644 index 0000000000000..008f2577c7992 --- /dev/null +++ b/tests/baselines/reference/tupleComplexity.errors.txt @@ -0,0 +1,59 @@ +tupleComplexity.ts(43,7): error TS2322: Type '[string, number]' is not assignable to type '[string, number, boolean]'. + Source has 2 element(s) but target requires 3. +tupleComplexity.ts(44,36): error TS2322: Type 'number' is not assignable to type 'string'. +tupleComplexity.ts(44,40): error TS2322: Type 'boolean' is not assignable to type 'string'. + + +==== tupleComplexity.ts (3 errors) ==== + // Tests for TS2590: "Expression produces a union type that is too complex to represent" + + // --- Tuple Unions --- + + // Simple union - Should work + type TupleUnion1 = [string, number] | [boolean, string]; + const valid1: TupleUnion1 = ["hello", 42]; // ✅ Should pass + const valid2: TupleUnion1 = [true, "world"]; // ✅ Should pass + + // Extended union - Should trigger TS2590 + type TupleUnion2 = [string, number] | [boolean, string]; + type ComplexTuple = [...TupleUnion2, string]; // ❌ Should trigger TS2590 + const invalid: ComplexTuple = ["hello", 42, "world"]; // Should fail with TS2590 + + // --- Tuple Concatenations --- + + // Manageable concatenation - Should work + type ConcatTuple = [...T, ...U]; + type Result1 = ConcatTuple<[string, number], [boolean]>; // ✅ Should infer [string, number, boolean] + const concat1: Result1 = ["hello", 42, true]; // ✅ Should pass + + // Excessively large concatenation - Should trigger TS2590 + type LargeConcat = ConcatTuple<[...Array<100>], [...Array<100>]>; + // ❌ Should trigger TS2590 for excessive complexity + + // --- Mapped Types on Tuples --- + + // Simple mapping - Should work + type Stringify = { [K in keyof T]: string }; + type MappedTuple1 = Stringify<[number, boolean]>; // ✅ Should infer [string, string] + const map1: MappedTuple1 = ["42", "true"]; // ✅ Should pass + + // --- Nested Tuples --- + + // Deeply nested tuple - Should trigger TS2590 + type DeepTuple = [string, [boolean | number, [boolean | number, [boolean | number]]]]; + type Nested = [...DeepTuple, string]; // ❌ Should trigger TS2590 + const deep: Nested = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 + + // --- Invalid Cases --- + + // Expected type mismatches (non-TS2590 failures) + const invalidConcat1: Result1 = ["hello", 42]; // ❌ Error: Missing boolean + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '[string, number]' is not assignable to type '[string, number, boolean]'. +!!! error TS2322: Source has 2 element(s) but target requires 3. + const invalidMap1: MappedTuple1 = [42, true]; // ❌ Error: Expected strings + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~~~ +!!! error TS2322: Type 'boolean' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/tupleComplexity.js b/tests/baselines/reference/tupleComplexity.js new file mode 100644 index 0000000000000..c75c2e0151d48 --- /dev/null +++ b/tests/baselines/reference/tupleComplexity.js @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/tupleComplexity.ts] //// + +//// [tupleComplexity.ts] +// Tests for TS2590: "Expression produces a union type that is too complex to represent" + +// --- Tuple Unions --- + +// Simple union - Should work +type TupleUnion1 = [string, number] | [boolean, string]; +const valid1: TupleUnion1 = ["hello", 42]; // ✅ Should pass +const valid2: TupleUnion1 = [true, "world"]; // ✅ Should pass + +// Extended union - Should trigger TS2590 +type TupleUnion2 = [string, number] | [boolean, string]; +type ComplexTuple = [...TupleUnion2, string]; // ❌ Should trigger TS2590 +const invalid: ComplexTuple = ["hello", 42, "world"]; // Should fail with TS2590 + +// --- Tuple Concatenations --- + +// Manageable concatenation - Should work +type ConcatTuple = [...T, ...U]; +type Result1 = ConcatTuple<[string, number], [boolean]>; // ✅ Should infer [string, number, boolean] +const concat1: Result1 = ["hello", 42, true]; // ✅ Should pass + +// Excessively large concatenation - Should trigger TS2590 +type LargeConcat = ConcatTuple<[...Array<100>], [...Array<100>]>; +// ❌ Should trigger TS2590 for excessive complexity + +// --- Mapped Types on Tuples --- + +// Simple mapping - Should work +type Stringify = { [K in keyof T]: string }; +type MappedTuple1 = Stringify<[number, boolean]>; // ✅ Should infer [string, string] +const map1: MappedTuple1 = ["42", "true"]; // ✅ Should pass + +// --- Nested Tuples --- + +// Deeply nested tuple - Should trigger TS2590 +type DeepTuple = [string, [boolean | number, [boolean | number, [boolean | number]]]]; +type Nested = [...DeepTuple, string]; // ❌ Should trigger TS2590 +const deep: Nested = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 + +// --- Invalid Cases --- + +// Expected type mismatches (non-TS2590 failures) +const invalidConcat1: Result1 = ["hello", 42]; // ❌ Error: Missing boolean +const invalidMap1: MappedTuple1 = [42, true]; // ❌ Error: Expected strings + + +//// [tupleComplexity.js] +// Tests for TS2590: "Expression produces a union type that is too complex to represent" +var valid1 = ["hello", 42]; // ✅ Should pass +var valid2 = [true, "world"]; // ✅ Should pass +var invalid = ["hello", 42, "world"]; // Should fail with TS2590 +var concat1 = ["hello", 42, true]; // ✅ Should pass +var map1 = ["42", "true"]; // ✅ Should pass +var deep = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 +// --- Invalid Cases --- +// Expected type mismatches (non-TS2590 failures) +var invalidConcat1 = ["hello", 42]; // ❌ Error: Missing boolean +var invalidMap1 = [42, true]; // ❌ Error: Expected strings diff --git a/tests/baselines/reference/tupleComplexity.symbols b/tests/baselines/reference/tupleComplexity.symbols new file mode 100644 index 0000000000000..34054917e62b0 --- /dev/null +++ b/tests/baselines/reference/tupleComplexity.symbols @@ -0,0 +1,100 @@ +//// [tests/cases/compiler/tupleComplexity.ts] //// + +=== tupleComplexity.ts === +// Tests for TS2590: "Expression produces a union type that is too complex to represent" + +// --- Tuple Unions --- + +// Simple union - Should work +type TupleUnion1 = [string, number] | [boolean, string]; +>TupleUnion1 : Symbol(TupleUnion1, Decl(tupleComplexity.ts, 0, 0)) + +const valid1: TupleUnion1 = ["hello", 42]; // ✅ Should pass +>valid1 : Symbol(valid1, Decl(tupleComplexity.ts, 6, 5)) +>TupleUnion1 : Symbol(TupleUnion1, Decl(tupleComplexity.ts, 0, 0)) + +const valid2: TupleUnion1 = [true, "world"]; // ✅ Should pass +>valid2 : Symbol(valid2, Decl(tupleComplexity.ts, 7, 5)) +>TupleUnion1 : Symbol(TupleUnion1, Decl(tupleComplexity.ts, 0, 0)) + +// Extended union - Should trigger TS2590 +type TupleUnion2 = [string, number] | [boolean, string]; +>TupleUnion2 : Symbol(TupleUnion2, Decl(tupleComplexity.ts, 7, 44)) + +type ComplexTuple = [...TupleUnion2, string]; // ❌ Should trigger TS2590 +>ComplexTuple : Symbol(ComplexTuple, Decl(tupleComplexity.ts, 10, 56)) +>TupleUnion2 : Symbol(TupleUnion2, Decl(tupleComplexity.ts, 7, 44)) + +const invalid: ComplexTuple = ["hello", 42, "world"]; // Should fail with TS2590 +>invalid : Symbol(invalid, Decl(tupleComplexity.ts, 12, 5)) +>ComplexTuple : Symbol(ComplexTuple, Decl(tupleComplexity.ts, 10, 56)) + +// --- Tuple Concatenations --- + +// Manageable concatenation - Should work +type ConcatTuple = [...T, ...U]; +>ConcatTuple : Symbol(ConcatTuple, Decl(tupleComplexity.ts, 12, 53)) +>T : Symbol(T, Decl(tupleComplexity.ts, 17, 17)) +>U : Symbol(U, Decl(tupleComplexity.ts, 17, 33)) +>T : Symbol(T, Decl(tupleComplexity.ts, 17, 17)) +>U : Symbol(U, Decl(tupleComplexity.ts, 17, 33)) + +type Result1 = ConcatTuple<[string, number], [boolean]>; // ✅ Should infer [string, number, boolean] +>Result1 : Symbol(Result1, Decl(tupleComplexity.ts, 17, 66)) +>ConcatTuple : Symbol(ConcatTuple, Decl(tupleComplexity.ts, 12, 53)) + +const concat1: Result1 = ["hello", 42, true]; // ✅ Should pass +>concat1 : Symbol(concat1, Decl(tupleComplexity.ts, 19, 5)) +>Result1 : Symbol(Result1, Decl(tupleComplexity.ts, 17, 66)) + +// Excessively large concatenation - Should trigger TS2590 +type LargeConcat = ConcatTuple<[...Array<100>], [...Array<100>]>; +>LargeConcat : Symbol(LargeConcat, Decl(tupleComplexity.ts, 19, 45)) +>ConcatTuple : Symbol(ConcatTuple, Decl(tupleComplexity.ts, 12, 53)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +// ❌ Should trigger TS2590 for excessive complexity + +// --- Mapped Types on Tuples --- + +// Simple mapping - Should work +type Stringify = { [K in keyof T]: string }; +>Stringify : Symbol(Stringify, Decl(tupleComplexity.ts, 22, 65)) +>T : Symbol(T, Decl(tupleComplexity.ts, 28, 15)) +>K : Symbol(K, Decl(tupleComplexity.ts, 28, 37)) +>T : Symbol(T, Decl(tupleComplexity.ts, 28, 15)) + +type MappedTuple1 = Stringify<[number, boolean]>; // ✅ Should infer [string, string] +>MappedTuple1 : Symbol(MappedTuple1, Decl(tupleComplexity.ts, 28, 61)) +>Stringify : Symbol(Stringify, Decl(tupleComplexity.ts, 22, 65)) + +const map1: MappedTuple1 = ["42", "true"]; // ✅ Should pass +>map1 : Symbol(map1, Decl(tupleComplexity.ts, 30, 5)) +>MappedTuple1 : Symbol(MappedTuple1, Decl(tupleComplexity.ts, 28, 61)) + +// --- Nested Tuples --- + +// Deeply nested tuple - Should trigger TS2590 +type DeepTuple = [string, [boolean | number, [boolean | number, [boolean | number]]]]; +>DeepTuple : Symbol(DeepTuple, Decl(tupleComplexity.ts, 30, 42)) + +type Nested = [...DeepTuple, string]; // ❌ Should trigger TS2590 +>Nested : Symbol(Nested, Decl(tupleComplexity.ts, 35, 86)) +>DeepTuple : Symbol(DeepTuple, Decl(tupleComplexity.ts, 30, 42)) + +const deep: Nested = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 +>deep : Symbol(deep, Decl(tupleComplexity.ts, 37, 5)) +>Nested : Symbol(Nested, Decl(tupleComplexity.ts, 35, 86)) + +// --- Invalid Cases --- + +// Expected type mismatches (non-TS2590 failures) +const invalidConcat1: Result1 = ["hello", 42]; // ❌ Error: Missing boolean +>invalidConcat1 : Symbol(invalidConcat1, Decl(tupleComplexity.ts, 42, 5)) +>Result1 : Symbol(Result1, Decl(tupleComplexity.ts, 17, 66)) + +const invalidMap1: MappedTuple1 = [42, true]; // ❌ Error: Expected strings +>invalidMap1 : Symbol(invalidMap1, Decl(tupleComplexity.ts, 43, 5)) +>MappedTuple1 : Symbol(MappedTuple1, Decl(tupleComplexity.ts, 28, 61)) + diff --git a/tests/baselines/reference/tupleComplexity.types b/tests/baselines/reference/tupleComplexity.types new file mode 100644 index 0000000000000..721aa59a83b27 --- /dev/null +++ b/tests/baselines/reference/tupleComplexity.types @@ -0,0 +1,160 @@ +//// [tests/cases/compiler/tupleComplexity.ts] //// + +=== tupleComplexity.ts === +// Tests for TS2590: "Expression produces a union type that is too complex to represent" + +// --- Tuple Unions --- + +// Simple union - Should work +type TupleUnion1 = [string, number] | [boolean, string]; +>TupleUnion1 : TupleUnion1 +> : ^^^^^^^^^^^ + +const valid1: TupleUnion1 = ["hello", 42]; // ✅ Should pass +>valid1 : TupleUnion1 +> : ^^^^^^^^^^^ +>["hello", 42] : [string, number] +> : ^^^^^^^^^^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>42 : 42 +> : ^^ + +const valid2: TupleUnion1 = [true, "world"]; // ✅ Should pass +>valid2 : TupleUnion1 +> : ^^^^^^^^^^^ +>[true, "world"] : [true, string] +> : ^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>"world" : "world" +> : ^^^^^^^ + +// Extended union - Should trigger TS2590 +type TupleUnion2 = [string, number] | [boolean, string]; +>TupleUnion2 : TupleUnion2 +> : ^^^^^^^^^^^ + +type ComplexTuple = [...TupleUnion2, string]; // ❌ Should trigger TS2590 +>ComplexTuple : [string, number, string] | [boolean, string, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +const invalid: ComplexTuple = ["hello", 42, "world"]; // Should fail with TS2590 +>invalid : [string, number, string] | [boolean, string, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>["hello", 42, "world"] : [string, number, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>42 : 42 +> : ^^ +>"world" : "world" +> : ^^^^^^^ + +// --- Tuple Concatenations --- + +// Manageable concatenation - Should work +type ConcatTuple = [...T, ...U]; +>ConcatTuple : [...T, ...U] +> : ^^^^^^^^^^^^ + +type Result1 = ConcatTuple<[string, number], [boolean]>; // ✅ Should infer [string, number, boolean] +>Result1 : [string, number, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + +const concat1: Result1 = ["hello", 42, true]; // ✅ Should pass +>concat1 : [string, number, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>["hello", 42, true] : [string, number, true] +> : ^^^^^^^^^^^^^^^^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>42 : 42 +> : ^^ +>true : true +> : ^^^^ + +// Excessively large concatenation - Should trigger TS2590 +type LargeConcat = ConcatTuple<[...Array<100>], [...Array<100>]>; +>LargeConcat : 100[] +> : ^^^^^ + +// ❌ Should trigger TS2590 for excessive complexity + +// --- Mapped Types on Tuples --- + +// Simple mapping - Should work +type Stringify = { [K in keyof T]: string }; +>Stringify : Stringify +> : ^^^^^^^^^^^^ + +type MappedTuple1 = Stringify<[number, boolean]>; // ✅ Should infer [string, string] +>MappedTuple1 : [string, string] +> : ^^^^^^^^^^^^^^^^ + +const map1: MappedTuple1 = ["42", "true"]; // ✅ Should pass +>map1 : [string, string] +> : ^^^^^^^^^^^^^^^^ +>["42", "true"] : [string, string] +> : ^^^^^^^^^^^^^^^^ +>"42" : "42" +> : ^^^^ +>"true" : "true" +> : ^^^^^^ + +// --- Nested Tuples --- + +// Deeply nested tuple - Should trigger TS2590 +type DeepTuple = [string, [boolean | number, [boolean | number, [boolean | number]]]]; +>DeepTuple : DeepTuple +> : ^^^^^^^^^ + +type Nested = [...DeepTuple, string]; // ❌ Should trigger TS2590 +>Nested : [string, [number | boolean, [number | boolean, [number | boolean]]], string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +const deep: Nested = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 +>deep : [string, [number | boolean, [number | boolean, [number | boolean]]], string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>["root", [true, [42, [false]]], "leaf"] : [string, [true, [number, [false]]], string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"root" : "root" +> : ^^^^^^ +>[true, [42, [false]]] : [true, [number, [false]]] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>[42, [false]] : [number, [false]] +> : ^^^^^^^^^^^^^^^^^ +>42 : 42 +> : ^^ +>[false] : [false] +> : ^^^^^^^ +>false : false +> : ^^^^^ +>"leaf" : "leaf" +> : ^^^^^^ + +// --- Invalid Cases --- + +// Expected type mismatches (non-TS2590 failures) +const invalidConcat1: Result1 = ["hello", 42]; // ❌ Error: Missing boolean +>invalidConcat1 : [string, number, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>["hello", 42] : [string, number] +> : ^^^^^^^^^^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>42 : 42 +> : ^^ + +const invalidMap1: MappedTuple1 = [42, true]; // ❌ Error: Expected strings +>invalidMap1 : [string, string] +> : ^^^^^^^^^^^^^^^^ +>[42, true] : [number, boolean] +> : ^^^^^^^^^^^^^^^^^ +>42 : 42 +> : ^^ +>true : true +> : ^^^^ + diff --git a/tests/cases/compiler/tupleComplexity.ts b/tests/cases/compiler/tupleComplexity.ts new file mode 100644 index 0000000000000..c58911da01834 --- /dev/null +++ b/tests/cases/compiler/tupleComplexity.ts @@ -0,0 +1,44 @@ +// Tests for TS2590: "Expression produces a union type that is too complex to represent" + +// --- Tuple Unions --- + +// Simple union - Should work +type TupleUnion1 = [string, number] | [boolean, string]; +const valid1: TupleUnion1 = ["hello", 42]; // ✅ Should pass +const valid2: TupleUnion1 = [true, "world"]; // ✅ Should pass + +// Extended union - Should trigger TS2590 +type TupleUnion2 = [string, number] | [boolean, string]; +type ComplexTuple = [...TupleUnion2, string]; // ❌ Should trigger TS2590 +const invalid: ComplexTuple = ["hello", 42, "world"]; // Should fail with TS2590 + +// --- Tuple Concatenations --- + +// Manageable concatenation - Should work +type ConcatTuple = [...T, ...U]; +type Result1 = ConcatTuple<[string, number], [boolean]>; // ✅ Should infer [string, number, boolean] +const concat1: Result1 = ["hello", 42, true]; // ✅ Should pass + +// Excessively large concatenation - Should trigger TS2590 +type LargeConcat = ConcatTuple<[...Array<100>], [...Array<100>]>; +// ❌ Should trigger TS2590 for excessive complexity + +// --- Mapped Types on Tuples --- + +// Simple mapping - Should work +type Stringify = { [K in keyof T]: string }; +type MappedTuple1 = Stringify<[number, boolean]>; // ✅ Should infer [string, string] +const map1: MappedTuple1 = ["42", "true"]; // ✅ Should pass + +// --- Nested Tuples --- + +// Deeply nested tuple - Should trigger TS2590 +type DeepTuple = [string, [boolean | number, [boolean | number, [boolean | number]]]]; +type Nested = [...DeepTuple, string]; // ❌ Should trigger TS2590 +const deep: Nested = ["root", [true, [42, [false]]], "leaf"]; // Should fail with TS2590 + +// --- Invalid Cases --- + +// Expected type mismatches (non-TS2590 failures) +const invalidConcat1: Result1 = ["hello", 42]; // ❌ Error: Missing boolean +const invalidMap1: MappedTuple1 = [42, true]; // ❌ Error: Expected strings