From ae6c587fc4cff399ca15331ca0d2d997be6c557a Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Tue, 16 Jun 2026 20:39:12 +0000 Subject: [PATCH] fix(generate-types): preserve infer inside tuple types in extends clause Render tuple types in conditional `extends` position element-wise so `infer` in an element or rest slot survives instead of collapsing to a free type reference, which produced invalid types.d.ts (TS2304). Fixes webpack/webpack#21191 --- generate-types/index.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/generate-types/index.js b/generate-types/index.js index 5a04f9b..6a639b8 100644 --- a/generate-types/index.js +++ b/generate-types/index.js @@ -2397,6 +2397,39 @@ const printError = (diagnostic) => { return symbol ? symbol.getName() : getCode(t, typeArgs, state); } + // Tuples in `extends` position must be rendered element-wise so that + // `infer` in an element/rest slot survives (getCode collapses it). + const objectFlags = + t.flags & ts.TypeFlags.Object + ? /** @type {ts.ObjectType} */ (t).objectFlags + : 0; + if (objectFlags & ts.ObjectFlags.Reference) { + const target = /** @type {ts.TypeReference} */ (t).target; + if ( + target && + /** @type {ts.ObjectType} */ (target).objectFlags & + ts.ObjectFlags.Tuple + ) { + const tupleTarget = /** @type {ts.TupleType} */ (target); + const elements = checker.getTypeArguments( + /** @type {ts.TypeReference} */ (t), + ); + const parts = elements.map((el, i) => { + const flag = tupleTarget.elementFlags[i]; + const inner = getExtendsString(el); + // Rest `...x[]` carries the element type; Variadic `...x` + // (incl. `...infer R`) carries the whole spread type. + if (flag & ts.ElementFlags.Rest) return `...(${inner})[]`; + if (flag & ts.ElementFlags.Variadic) return `...${inner}`; + if (flag & ts.ElementFlags.Optional) return `${inner}?`; + return inner; + }); + return `${tupleTarget.readonly ? "readonly " : ""}[${parts.join( + ", ", + )}]`; + } + } + if (checker.isArrayType(t)) { const elementType = t.typeArguments[0]; return "(" + getExtendsString(elementType) + ")[]";