[interop] Minor Fixes in Generics with Anonymous Closures (#447)

* Minor Fixes in Generics with Anonymous Closures

* added test, and made generic type list a set
diff --git a/web_generator/lib/src/ast/helpers.dart b/web_generator/lib/src/ast/helpers.dart
index 4d071e9..f509c71 100644
--- a/web_generator/lib/src/ast/helpers.dart
+++ b/web_generator/lib/src/ast/helpers.dart
@@ -160,8 +160,8 @@
 }
 
 /// Recursively get the generic types specified in a given type [t]
-List<GenericType> getGenericTypes(Type t) {
-  final types = <(String, Type?)>[];
+Set<GenericType> getGenericTypes(Type t) {
+  final types = <(String, Type?)>{};
   switch (t) {
     case GenericType():
       types.add((t.name, t.constraint));
@@ -250,7 +250,7 @@
 
   // Types are cloned so that modifications to constraints can happen without
   // affecting initial references
-  return types.map((t) => GenericType(name: t.$1, constraint: t.$2)).toList();
+  return types.map((t) => GenericType(name: t.$1, constraint: t.$2)).toSet();
 }
 
 Type desugarTypeAliases(Type t) {
diff --git a/web_generator/lib/src/ast/types.dart b/web_generator/lib/src/ast/types.dart
index 5e5552a..4bc6bb8 100644
--- a/web_generator/lib/src/ast/types.dart
+++ b/web_generator/lib/src/ast/types.dart
@@ -337,13 +337,24 @@
     this.typeParameters = const [],
     this.parameters = const [],
     this.isNullable = false,
-  }) : declarationName = name;
+  }) : declarationName = name {
+    if (typeParameters.isEmpty) {
+      typeParameters.addAll(getGenericTypes(this).map((t) {
+        t.constraint ??= BuiltinType.anyType;
+        return t;
+      }));
+    }
+  }
 
   @override
   Reference emit([TypeOptions? options]) {
     return TypeReference((t) => t
       ..symbol = declarationName
-      ..isNullable = options?.nullable ?? isNullable);
+      ..isNullable = options?.nullable ?? isNullable
+      ..types.addAll(typeParameters.map((t) {
+        final clonedT = GenericType(name: t.name, isNullable: t.isNullable);
+        return clonedT.emit(options);
+      })));
   }
 }
 
@@ -388,8 +399,7 @@
                 name: 'call',
                 id: const ID(type: 'fun', name: 'call'),
                 returnType: returnType,
-                parameters: parameters,
-                typeParameters: typeParameters)
+                parameters: parameters)
           ]);
 }
 
@@ -445,8 +455,6 @@
           .addAll(typeParameters.map((t) => t.emit(options?.toTypeOptions())))
       ..methods.add(Method((m) => m
         ..name = 'call'
-        ..types
-            .addAll(typeParameters.map((t) => t.emit(options?.toTypeOptions())))
         ..returns = returnType.emit(options?.toTypeOptions())
         ..requiredParameters.addAll(requiredParams)
         ..optionalParameters.addAll(optionalParams)
diff --git a/web_generator/test/integration/interop_gen/ts_typing_expected.dart b/web_generator/test/integration/interop_gen/ts_typing_expected.dart
index 9962ca3..c583c9b 100644
--- a/web_generator/test/integration/interop_gen/ts_typing_expected.dart
+++ b/web_generator/test/integration/interop_gen/ts_typing_expected.dart
@@ -33,6 +33,7 @@
 
   static const MyEnum D = MyEnum._(4);
 }
+typedef Transformer<T extends _i1.JSAny?> = _AnonymousFunction_5293571<T>;
 @_i1.JS()
 external _i1.JSFunction copyOfmyEnclosingFunction;
 @_i1.JS()
@@ -112,6 +113,10 @@
 
   external T value;
 }
+extension type _AnonymousFunction_5293571<T extends _i1.JSAny?>._(
+    _i1.JSFunction _) implements _i1.JSFunction {
+  external ComposedType<T> call(T object);
+}
 extension type ComposedType<T extends _i1.JSAny?>._(_i1.JSObject _)
     implements _i1.JSObject {
   external T enclosed;
diff --git a/web_generator/test/integration/interop_gen/ts_typing_input.d.ts b/web_generator/test/integration/interop_gen/ts_typing_input.d.ts
index b47a6cc..713db27 100644
--- a/web_generator/test/integration/interop_gen/ts_typing_input.d.ts
+++ b/web_generator/test/integration/interop_gen/ts_typing_input.d.ts
@@ -11,6 +11,7 @@
 interface ComposedType<T = any> {
     enclosed: T;
 }
+export type Transformer<T> = (object: T) => ComposedType<T>;
 export declare let copyOfmyEnclosingFunction: typeof myEnclosingFunction;
 export declare const myEnumValue: MyEnum;
 export declare const myEnumValue2: typeof MyEnum;