#Issue with Type Generic not bubbling up

4 messages · Page 1 of 1 (latest)

ripe hedge
#
import { Type } from "@nestjs/common";
/**
* Type = interface Type<T = any> extends Function {
    new (...args: any[]): T;
}
*/
/**
 * Stores references to input types created recursively.
 */
export function memoizeInputClass<T, ReturnType>(
  keyGenerator: (classRef: Type) => string,
  fn: (
    key: string,
    EntityClass: Type<T>,
    classRef: Type<ReturnType>,
  ) => Type<ReturnType>,
): (classRef: Type<T>) => Type<ReturnType> {
  const typeStorage = new Map<string, Type<ReturnType>>();
  return function (classRef: Type<T>) {
    const key = keyGenerator(classRef);
    const mappedValue = typeStorage.get(key);
    if (mappedValue) {
      return mappedValue;
    }
    const classConst = class {} as Type<ReturnType>;
    Object.defineProperty(classConst, "name", {
      value: key,
    });
    typeStorage.set(key, classConst);
    return fn(key, classRef, classConst);
  };
}
#
import { QueryOrder } from "@mikro-orm/core";
import { Type } from "@nestjs/common";
import { Field, InputType, registerEnumType } from "@nestjs/graphql";
import { getFieldsAndDecoratorForType } from "@nestjs/graphql/dist/schema-builder/utils/get-fields-and-decorator.util";
import { memoizeInputClass } from "../../storages/input-class.storage";

export type IOrderByInput<T> = {
  [K in keyof T]: QueryOrder;
};

/**
 * Allows us to create an InputType for MikroORM entities that applies each
 * field with the QueryOrder enum field value type.
 */
const OrderByInput = memoizeInputClass(
  (classRef) => `${classRef.name}OrderByInput`,
  function <T>(
    inputName: string,
    TClass: Type<T>,
    OrderByType: Type<IOrderByInput<T>>,
  ): Type<IOrderByInput<T>> {
    const { fields } = getFieldsAndDecoratorForType(TClass);

    InputType(inputName)(OrderByType);

    fields.forEach((item) => {
      const returnType = item.extensions?.relation
        ? OrderByInput(item.typeFn() as Type)
        : QueryOrder;

      /**
       * Takes the field name and dictates that GraphQL expects a `QueryOrder`
       * as the value input
       */
      Field(() => returnType, { nullable: true })(
        OrderByType.prototype,
        item.name,
      );
    });

    return OrderByType;
  },
);

export { OrderByInput };
#

However, when I attempt to use OrderByInput, I get the following:

@ObjectType()
class Foo {
  @Field(() => ID)
  id: number;
}

@InputType()
class FooOrderByInput extends OrderByInput(Foo) {} // const OrderByInput: (classRef: Type<unknown>) => Type<unknown>

How can I resolve this so that it instead returns const OrderByInput: (classRef: Type<Foo>) => Type<IOrderByInput<Foo>> when calling OrderByInput(Foo)?

#

I'm sure it's due to how I've defined momoizeInputClass, but I'm unsure how