From 685cd3e1fcb67665f07e7ed6a79da694b19427e7 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Mon, 4 Jan 2021 12:04:42 -0700 Subject: [PATCH] fix: Crash when converting a generic with a tuple constraint Closes #1449 --- src/lib/converter/types.ts | 16 +-- src/test/converter/types/specs.json | 160 ++++++++++++++++++++-------- src/test/converter/types/tuple.ts | 4 + 3 files changed, 130 insertions(+), 50 deletions(-) diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index ad9d633a3..b311f16cc 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -805,13 +805,17 @@ const tupleConverter: TypeConverter = { return new TupleType(elements); }, convertType(context, type, node) { - let elements = type.typeArguments?.map((type) => - convertType(context, type) - ); + // TS 3.9 support + const elementTypes = node.elements ?? (node as any).elementTypes; + // We need to do this because of type argument constraints, see GH1449 + const types = type.typeArguments?.slice(0, elementTypes.length); + let elements = types?.map((type) => convertType(context, type)); - // elements was called elementTypes in TS 3.9. - // 3.9 doesn't have tuple members, so it's fine to skip this there. - if (node.elements && node.elements.every(ts.isNamedTupleMember)) { + // 3.9 doesn't have named tuple members, so it's fine to skip this there. + if ( + ts.isNamedTupleMember && + elementTypes.every(ts.isNamedTupleMember) + ) { const namedMembers = node.elements as readonly ts.NamedTupleMember[]; elements = elements?.map( (el, i) => diff --git a/src/test/converter/types/specs.json b/src/test/converter/types/specs.json index aa65d1edd..5d185f133 100644 --- a/src/test/converter/types/specs.json +++ b/src/test/converter/types/specs.json @@ -569,7 +569,7 @@ "flags": {}, "children": [ { - "id": 32, + "id": 36, "name": "NamedTuple", "kind": 4194304, "kindString": "Type alias", @@ -599,7 +599,7 @@ } }, { - "id": 33, + "id": 37, "name": "namedTuple", "kind": 32, "kindString": "Variable", @@ -630,6 +630,71 @@ ] }, "defaultValue": "..." + }, + { + "id": 32, + "name": "gh1449", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 33, + "name": "gh1449", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "typeParameter": [ + { + "id": 34, + "name": "T", + "kind": 131072, + "kindString": "Type parameter", + "flags": {}, + "type": { + "type": "tuple", + "elements": [ + { + "type": "named-tuple-member", + "name": "foo", + "isOptional": false, + "element": { + "type": "intrinsic", + "name": "any" + } + }, + { + "type": "named-tuple-member", + "name": "bar", + "isOptional": true, + "element": { + "type": "intrinsic", + "name": "any" + } + } + ] + } + } + ], + "parameters": [ + { + "id": 35, + "name": "a", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "T" + } + } + ], + "type": { + "type": "reference", + "name": "T" + } + } + ] } ], "groups": [ @@ -637,27 +702,34 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 32 + 36 ] }, { "title": "Variables", "kind": 32, "children": [ - 33 + 37 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 32 ] } ] }, { - "id": 34, + "id": 38, "name": "type-operator", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 36, + "id": 40, "name": "B", "kind": 4194304, "kindString": "Type alias", @@ -675,7 +747,7 @@ } }, { - "id": 37, + "id": 41, "name": "C", "kind": 4194304, "kindString": "Type alias", @@ -683,14 +755,14 @@ "type": { "type": "reflection", "declaration": { - "id": 38, + "id": 42, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "children": [ { - "id": 39, + "id": 43, "name": "prop1", "kind": 1024, "kindString": "Property", @@ -701,7 +773,7 @@ } }, { - "id": 40, + "id": 44, "name": "prop2", "kind": 1024, "kindString": "Property", @@ -717,8 +789,8 @@ "title": "Properties", "kind": 1024, "children": [ - 39, - 40 + 43, + 44 ] } ] @@ -726,7 +798,7 @@ } }, { - "id": 41, + "id": 45, "name": "D", "kind": 4194304, "kindString": "Type alias", @@ -736,13 +808,13 @@ "operator": "keyof", "target": { "type": "reference", - "id": 37, + "id": 41, "name": "C" } } }, { - "id": 35, + "id": 39, "name": "a", "kind": 32, "kindString": "Variable", @@ -765,29 +837,29 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 36, - 37, - 41 + 40, + 41, + 45 ] }, { "title": "Variables", "kind": 32, "children": [ - 35 + 39 ] } ] }, { - "id": 42, + "id": 46, "name": "union-or-intersection", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 43, + "id": 47, "name": "FirstType", "kind": 256, "kindString": "Interface", @@ -797,7 +869,7 @@ }, "children": [ { - "id": 44, + "id": 48, "name": "firstProperty", "kind": 1024, "kindString": "Property", @@ -816,13 +888,13 @@ "title": "Properties", "kind": 1024, "children": [ - 44 + 48 ] } ] }, { - "id": 45, + "id": 49, "name": "SecondType", "kind": 256, "kindString": "Interface", @@ -832,7 +904,7 @@ }, "children": [ { - "id": 46, + "id": 50, "name": "secondProperty", "kind": 1024, "kindString": "Property", @@ -851,13 +923,13 @@ "title": "Properties", "kind": 1024, "children": [ - 46 + 50 ] } ] }, { - "id": 47, + "id": 51, "name": "ThirdType", "kind": 256, "kindString": "Interface", @@ -867,7 +939,7 @@ }, "children": [ { - "id": 50, + "id": 54, "name": "thirdComplexProperty", "kind": 1024, "kindString": "Property", @@ -891,12 +963,12 @@ "types": [ { "type": "reference", - "id": 43, + "id": 47, "name": "FirstType" }, { "type": "reference", - "id": 45, + "id": 49, "name": "SecondType" } ] @@ -907,7 +979,7 @@ } }, { - "id": 49, + "id": 53, "name": "thirdIntersectionProperty", "kind": 1024, "kindString": "Property", @@ -920,19 +992,19 @@ "types": [ { "type": "reference", - "id": 43, + "id": 47, "name": "FirstType" }, { "type": "reference", - "id": 47, + "id": 51, "name": "ThirdType" } ] } }, { - "id": 48, + "id": 52, "name": "thirdUnionProperty", "kind": 1024, "kindString": "Property", @@ -945,12 +1017,12 @@ "types": [ { "type": "reference", - "id": 43, + "id": 47, "name": "FirstType" }, { "type": "reference", - "id": 45, + "id": 49, "name": "SecondType" } ] @@ -962,9 +1034,9 @@ "title": "Properties", "kind": 1024, "children": [ - 50, - 49, - 48 + 54, + 53, + 52 ] } ] @@ -975,9 +1047,9 @@ "title": "Interfaces", "kind": 256, "children": [ - 43, - 45, - 47 + 47, + 49, + 51 ] } ] @@ -993,8 +1065,8 @@ 24, 28, 31, - 34, - 42 + 38, + 46 ] } ] diff --git a/src/test/converter/types/tuple.ts b/src/test/converter/types/tuple.ts index a7363c79e..09a49ea78 100644 --- a/src/test/converter/types/tuple.ts +++ b/src/test/converter/types/tuple.ts @@ -6,3 +6,7 @@ export const namedTuple = returnMapped(); function returnMapped() { return ({} as any) as { [K in keyof T]: T[K] }; } + +export function gh1449(a: T): T { + return a; +}