Ввод возврата метода Factory, который применяет миксины на основе аргументов. - PullRequest
0 голосов
/ 23 октября 2019

Я пытаюсь создать метод Factory в TypeScript, который создает класс (экземпляр) с несколькими примененными миксинами на основе одного из аргументов метода Factory.

Это код, переносимый из простого JavaScript. Функционально он работает нормально, просто TypeScript не «распознает» происходящие динамические вещи, поэтому он не знает returnType фабричного метода.

Это код, который у меня есть на данный момент, и япытаюсь заставить TypeScript каким-то образом узнать returnType метода ServiceFactory, который, по крайней мере, всегда BaseModel, но в зависимости от значения параметра операций, также дополнен такими интерфейсами, как ICreatable.


const OPERATIONS = Object.freeze({
  /** Only HTTP GET support (methods: all and show) */
  DEFAULT: 0,
  /** HTTP POST (method: create */
  CREATE: 1,
  /** HTTP PATCH (method: update */
  UPDATE: 2,
  /** both HTTP POST & PATCH  (methods: create & update */
  CREATE_AND_UPDATE: 3,
  /** HTTP PUT (method: replace */
  REPLACEABLE: 4,
  /** HTTP DELETE (method: delete */
  DELETE: 8,
  /** HTTP GET, POST, PUT, PATCH & DELETE (methods: all, show, create, replace, update & delete) */
  ALL: 15,
});

type Constructor<T = {}> = new (...args: any[]) => T;

export interface ICreatable {
  create(requestContext:object, body: object, options:object): Promise<object>
}

export class BaseModel {}

export const Creatable = <T extends Constructor<BaseModel>>(Sup: T) => class extends Sup implements ICreatable {
  async create(): Promise<object> {
    return ...;
  }
};

export function ServiceFactory(name: string, operations = OPERATIONS.DEFAULT): BaseModel {
  let Clazz = { [name]: class extends BaseModel {} }[name]; // https://stackoverflow.com/questions/33605775/es6-dynamic-class-names/33611096

  //if (operations & OPERATIONS.UPDATE) {
  //  Clazz = Updatable(Clazz);
  //}
  if (operations & OPERATIONS.CREATE) {
    Clazz = Creatable(Clazz);
  }
  //if (operations & OPERATIONS.DELETE) {
  //  Clazz = Deletable(Clazz);
  //}
  //if (operations & OPERATIONS.REPLACEABLE) {
  //  Clazz = Replaceable(Clazz);
  //}

  return new Clazz();
}


Когда яЧтобы вызвать приведенный ниже код, TypeScript должен знать, что у someNameClassInstance есть метод с именем 'create'

const someNameClassInstance = ServiceFactory('someName', OPERATIONS.CREATE)
someNameClassInstance. //auto complete should yield 'create'
``

1 Ответ

0 голосов
/ 23 октября 2019

Я не знаю ваш вариант использования и необходимость динамических классов, но как насчет использования обобщений для быстрого решения:

export function ServiceFactory<T extends BaseModel>(name: string, operations = OPERATIONS.DEFAULT): T {
}
type MyType = {create: (oneArg: string, otherArg: number) => boolean}

const someNameClassInstance = ServiceFactory<MyType>('someName', OPERATIONS.CREATE)
someNameClassInstance // yields code insight create

для более надежного решения, я думаю, что рефакторинг самой фабрикиэто путь.

...