Búsqueda de sitios web

¿Cómo hacer cumplir las dependencias de tipo entre las propiedades de un objeto en los parámetros de una función de TypeScript?


Estoy intentando crear una función que tome un parámetro P, que es un objeto con las siguientes limitaciones:

  • P puede tener una propiedad de tipo Transformers que se define como { [key in keyof T]?: (value: unknown) => unknown }
  • P puede tener una propiedad de tipo Comparers que se define como { [key in keyof T]?: (obj: T, key: keyof T, value: T[key]) => boolean }
  • Si P tiene tanto Transformers como Comparers, para las claves que aparecen en ambos, el valor de esa clave en Comparers debería basarse en el valor devuelto del Transformer correspondiente.

Ejemplo :

type T1 = { a: string; b: number; c: Date }
type Transformers<T> = { [key in keyof T]?: (value: unknown) => unknown };
type Comparers<T> = { [key in keyof T]?: (obj: T, key: keyof T, value: T[key]) => boolean };
declare function MyFunc<T>(P: {
  transformers: Transformers<T>,
  comparers: Comparers<T>
}
MyFunc<T1>({
  transformers: {
    c: (value: number) => {
      const from = new Date();
      const to = new Date();
      from.setMinutes(from.getMinutes() - value);
      return { from, to };
    }
  },
  comparers: {
    a: (obj: T, value: string) => obj.a.startsWith(value),
    c: (obj: T, value: { from: Date, to: Date }) => obj.c > value.from && obj[key] < value.to,
  }
})

Esto, por supuesto, genera un error de TypeScript en la línea 19 porque el value para c en comparers no coincide con el tipo de T.c.

Mi intento más cercano de crear un tipo para esto hasta ahora:

type Transformer = (...args: unknown[]) => unknown;
type Transformers<T> = { [key in keyof T]?: Transformer };
type t1 = { a: number; b: string; c: Date };

type Comparers<T, TR = undefined> = {
  [key in keyof T]?: (
    obj: T,
    value: key extends keyof TR
      ? TR[key] extends Transformer
        ? ReturnType<TR[key]>
        : T[key]
      : T[key]
  ) => boolean;
};

declare function Settings<T, TR extends Transformers<T>>(settings: {
  transformers?: TR;
  comparers: Comparers<T, TR>;
}): unknown;

const transformers = {
  b: (value: unknown) => Number(value),
  c: (value: unknown) => {
    const from = new Date();
    const to = new Date();
    from.setMinutes(from.getMinutes() - Number(value));
    return { from, to };
  },
};
Settings<t1, typeof transformers>({
  transformers,
  comparers: {
    a: (obj: t1, value: number) => {
      const val = obj.a;
      return val == value;
    },
    b: (obj: t1, value: number) => {
      const val = obj.b;
      return val.length >= value;
    },
    c: (obj: t1, value: { from: Date; to: Date }) => {
      const val = obj.c;
      return val > value.from && val < value.to;
    },
  },
});

Esto funciona, pero requiere que cree un objeto para Transformers y pase su tipo a la función.

¿Hay alguna manera de hacer las comprobaciones que estoy buscando dentro del tipo de parámetro de la función, con solo un genérico T siendo requerido, y el resto infiriéndose a partir de las propiedades del parámetro?