diff --git a/type-generation/src/astToIR.ts b/type-generation/src/astToIR.ts index 78cd17a..ced1193 100644 --- a/type-generation/src/astToIR.ts +++ b/type-generation/src/astToIR.ts @@ -15,6 +15,7 @@ import { SourceFile, SyntaxKind, ts, + TypeElementMemberedNode, TypeElementTypes, TypeLiteralNode, TypeNode, @@ -365,9 +366,15 @@ class SyntheticTypeConverter { } doConversion( - nodes: Pick[], + nodes: (TypeElementMemberedNode & Node)[], modifiers: Modifier, ): ReferenceTypeIR { + const res = nodes.filter( + (x): x is TypeElementMemberedNode & TypeParameteredNode & Node => + Node.isTypeParametered(x), + ); + const typeParams = this.converter.getTypeParamsFromDecls(res); + let name = this.nameContext.join("__"); if (!name.endsWith("_iface")) { name += "_iface"; @@ -384,7 +391,14 @@ class SyntheticTypeConverter { (x) => !Node.isPropertyNamed(x) || pickSet.has(x.getName()), ); } - const result = this.converter.interfaceToIR(name, [], members, [], [], []); + const result = this.converter.interfaceToIR( + name, + [], + members, + [], + [], + typeParams, + ); if (partial) { for (const prop of result.properties) { prop.isOptional = true; @@ -501,10 +515,6 @@ class SyntheticTypeConverter { } if (res.kind === "interfaces") { const { name, ifaces } = res; - const typeParams = this.converter.getTypeParamsFromDecls(ifaces); - if (typeParams.length > 0) { - throw new Error("Not handled"); - } this.nameContext.push(name); const result = this.doConversion(ifaces, modifiers); this.nameContext.pop(); diff --git a/type-generation/tests/a.test.ts b/type-generation/tests/a.test.ts index a38de89..d670ad0 100644 --- a/type-generation/tests/a.test.ts +++ b/type-generation/tests/a.test.ts @@ -1787,6 +1787,24 @@ describe("emit", () => { `).trim(), ); }); + it("PartialTypeArg", () => { + const res = emitFile(` + interface A { a: T; } + type D = Partial>; + declare function f(): D; + `); + assert.strictEqual( + removeTypeIgnores(res.slice(1).join("\n\n")), + dedent(` + type D = D__Partial__A_iface + + def f() -> D: ... + + class D__Partial__A_iface[T](Protocol): + a: T | None = ... + `).trim(), + ); + }); }); it("Composed type operators", () => { const res = emitFile(`