From 469ba1f711ace3a5ccd064ce55fdc92103a5a04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9A=A9=EC=A7=84?= Date: Tue, 24 Mar 2026 14:40:44 +0900 Subject: [PATCH] Fix crash when inferring from tuple with middle rest and trailing variadic elements When `getElementTypeOfSliceOfTupleType` returns `undefined` (because the implied arity from the variadic constraint consumes the entire source tuple), the result was passed directly to `inferFromTypes` via a non-null assertion, causing a `TypeError: Cannot read properties of undefined (reading 'aliasSymbol')` crash. Add null checks before calling `inferFromTypes` in both the `[...T, ...rest]` and `[...rest, ...T]` inference branches, consistent with the existing pattern used in the single-rest-element branch. Fixes #63005 --- src/compiler/checker.ts | 11 ++++++--- ...ixedTupleExtendsAtVariadicPosition.symbols | 23 +++++++++++++++++++ ...hFixedTupleExtendsAtVariadicPosition.types | 15 ++++++++++++ ...WithFixedTupleExtendsAtVariadicPosition.ts | 10 ++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0567712f11da3..cc51628c23c4e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27422,7 +27422,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (constraint && isTupleType(constraint) && !(constraint.target.combinedFlags & ElementFlags.Variable)) { const impliedArity = constraint.target.fixedLength; inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]); - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]); + const restType = getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength); + if (restType) { + inferFromTypes(restType, elementTypes[startLength + 1]); + } } } else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic) { @@ -27435,8 +27438,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed); const startIndex = endIndex - impliedArity; const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex), /*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex)); - - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]); + const restType = getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity); + if (restType) { + inferFromTypes(restType, elementTypes[startLength]); + } inferFromTypes(trailingSlice, elementTypes[startLength + 1]); } } diff --git a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.symbols b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.symbols index 2894444f81485..a17e7f8b343ab 100644 --- a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.symbols +++ b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.symbols @@ -160,3 +160,26 @@ type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVari >SubTup2TrailingVariadicWithTrailingFixedElementsTest2 : Symbol(SubTup2TrailingVariadicWithTrailingFixedElementsTest2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 68, 140)) >SubTup2TrailingVariadicWithTrailingFixedElements : Symbol(SubTup2TrailingVariadicWithTrailingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 58, 129)) +// repro #63005 - should not crash when implied arity consumes entire source tuple +type SubTup2RestAndTrailingVariadic3 = T extends [ +>SubTup2RestAndTrailingVariadic3 : Symbol(SubTup2RestAndTrailingVariadic3, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 69, 147)) +>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 72, 37)) +>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 72, 37)) + + ...(infer C)[], +>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 73, 13)) + + ...infer B extends [any, any, any] +>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 74, 12)) + +] + ? [C, ...B] +>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 73, 13)) +>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 74, 12)) + + : never; + +type SubTup2RestAndTrailingVariadic3Test = SubTup2RestAndTrailingVariadic3<[...a: 0[], b: 1, c: 2]>; +>SubTup2RestAndTrailingVariadic3Test : Symbol(SubTup2RestAndTrailingVariadic3Test, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 77, 12)) +>SubTup2RestAndTrailingVariadic3 : Symbol(SubTup2RestAndTrailingVariadic3, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 69, 147)) + diff --git a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types index 7bee1c64c4d44..055c5214d097e 100644 --- a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types +++ b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types @@ -119,3 +119,18 @@ type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVari >SubTup2TrailingVariadicWithTrailingFixedElementsTest2 : [c: 2, d: 3] > : ^^^^^^^^^^^^ +// repro #63005 - should not crash when implied arity consumes entire source tuple +type SubTup2RestAndTrailingVariadic3 = T extends [ +>SubTup2RestAndTrailingVariadic3 : SubTup2RestAndTrailingVariadic3 +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...(infer C)[], + ...infer B extends [any, any, any] +] + ? [C, ...B] + : never; + +type SubTup2RestAndTrailingVariadic3Test = SubTup2RestAndTrailingVariadic3<[...a: 0[], b: 1, c: 2]>; +>SubTup2RestAndTrailingVariadic3Test : never +> : ^^^^^ + diff --git a/tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts b/tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts index f5c47c9550dbc..4edf28bb04fc9 100644 --- a/tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts +++ b/tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts @@ -72,3 +72,13 @@ type SubTup2TrailingVariadicWithTrailingFixedElements = T e type SubTup2TrailingVariadicWithTrailingFixedElementsTest = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3]>; type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3, e: 4]>; + +// repro #63005 - should not crash when implied arity consumes entire source tuple +type SubTup2RestAndTrailingVariadic3 = T extends [ + ...(infer C)[], + ...infer B extends [any, any, any] +] + ? [C, ...B] + : never; + +type SubTup2RestAndTrailingVariadic3Test = SubTup2RestAndTrailingVariadic3<[...a: 0[], b: 1, c: 2]>;