Требовать класс для реализации метода с параметрами, основанными на обобщениях - PullRequest
1 голос
/ 30 июня 2019

У меня есть ClassDecorator, который принимает неопределенное количество параметров конструктора (<T>: { new (...args: any[]) => T }) и на основании этого я хочу, чтобы этот класс потребовал реализации метода с параметрами, отражающими типы этих предоставленных конструкторов.

Mydecorator:

type Constructor<T> = new (...args: any[]) => T;
type ComponentArray = Array<Constructor<unknown>>;

export interface TSystem<TComps extends ComponentArray> {
  handle: (...comps: TComps) => void;
}


export function System<TComps extends ComponentArray>(...comps: TComps) {
  return (ctor: Constructor<Required<TSystem<TComps>>>) => {
     // add metadata etc...
  };
}

Пример:


class RandomComponent {
  test1: string;
  // implementation ...
}

class RandomComponent2 {
  test2: string;
  // implementation ...
}

@System(RandomComponent, RandomComponent2 /* etc ... */)
class TestSystem {
  handle(r1: RandomComponent, r2: RandomComponent2 /* etc... */) {
    // handle components ...
  }
}

Я надеялся, что это сработает, однако компилятор выдаст мне эту ошибку:

Type '(comp: RandomComponent) => void' is not assignable 
to type '(comps_0: typeof RandomComponent) => void' 

Есть ли способ, которым я могуудалить typeof из интерфейса TSystem или, возможно, сделать это по-другому?Я хочу получить доступ к экземпляру класса, а не его тип.Или это просто ограничение системы типов TypeScript?

1 Ответ

2 голосов
/ 30 июня 2019

Этот код работает для меня на 3.5.1. Я опубликую его здесь, можете ли вы обновить свой вопрос, где ошибка, и я обновлю свой ответ. То, что вы описываете, определенно is возможно с Typescript.

https://typescript -play.js.org /? ExperimentalDecorators = истина # код / ​​C4TwDgpgBAwg9gOwM7AE4FcDGw6oDwAqAfFALxQIQDuUAFAHSMCGqA5kgFxRMIgDaAXQCUZEgQDcAKFCRYcALZhEEBMACCqVExBkoGrSDzoEAawRwqCIlMkQAHktTAoAS1URUAMyaZoBAMogKBDyhPCKSFD2wCoAJpHhSpSq + tokAN6SUFAAFjyxADYQXAyMmApgnFAEiUgipCQAbnAusVIAvpJd9o7OnsbYLohQgcGhNRWR0XEJFcopmmml9OURXBMRIpnZqBDA6KgIdNi4XPDIaFg4 + ABKEACO6C67sYSjMeO1RN-1GVnZ2QA9IDuLFYlB5HsmLEmMAmFFgJhGPR-u0Ol1MAUmEhIjd8gpEvNnNsoMC5Ioia5FEVIapYUMEJJOpIAALvEK0PEIWIEubJYBCSSY7GRAgQFDs + RQEl5blFWirMBcLk8 + SE-lbUkgqi4ExIf5AkHIqKxFzORWoplAA

EDIT: Изменить эту строку

  handle(comp: typeof RandomComponent) 

Я почти уверен, что должен сделать это с тем, что вы хотите, дайте мне знать.

EDIT2: я думаю, это то, что вы хотите.

type Constructor<T> = new (...args: any[]) => T;
type ComponentArray = Array<Constructor<unknown>>;

export interface TSystem<TComps extends ComponentArray> {
  handle: (...comps: ConvertInstanceTypes<TComps>) => void;
}

type ConvertInstanceTypes<T extends any[]> = {
  [K in keyof T]: T[K] extends Constructor<any> ? InstanceType<T[K]> : never;
}


export function System<TComps extends ComponentArray>(...comps: TComps) {
  return (ctor: Constructor<Required<TSystem<TComps>>>) => {
     // add metadata etc...
  };
}

class RandomComponent {
  test1: string = "test1";
  // implementation ...
}

class RandomComponent2 {
  test2: string = "test2";
  // implementation ...
}


@System(RandomComponent, RandomComponent2)
class TestSystem {
  handle(r1: InstanceType<typeof RandomComponent>, r2: InstanceType<typeof RandomComponent2>) {
    // handle components ...
  }
}
...