Введите для класса в качестве параметра функции

#typescript #types #casting #nestjs

#typescript #типы #Кастинг #nestjs

Вопрос:

Во-первых, вот основной интерфейс :

 // IMySuperInterface.interface.ts

export interface IMySuperInterface<T = any> {
  handle(arg?: any): Promise<T>;
}
 

По сути, мне просто нужен общий тип для ==> дочернего класса с функцией ‘handle’.
Что-то вроде :

 function MyDummyFunction (param: {{class that extends IMySuperInterface)}})
 

Я пытаюсь зарегистрировать все классы в моем приложении, которые реализуют мой «IMySyperInterface»

 // MySuperImplementation.service.ts
@Feature('ReferenceA')
export class MySuperImplementation
  implements IMySuperInterface {

 constructor(private readonly logger: myLoggerService) {
    this.logger.setContext(this);
  }

  async handle(someDummy: any): Promise<void> {
    ....
  }
}
 

И здесь определение декоратора

 // feature.decorator.ts
const _mapping = new Map<string, anyOrIdontKnowWhatToDo>();

export function Feature(key: string) {

  return function (target: **HERE WHAT CAN I WRITE  ??????**) {
    Feature.cache.set(key, target);
    return target;
  };
}
 

Я пытаюсь найти какой-то «по крайней мере, содержит <IMySuperInterface>» или тип <IMySuperInterface>

с

 export interface Type<T = any> extends Function {
    new (...args: any[]): T;
}
 

Но я получаю :

  • ни то, ни другое: извините, но ‘prototype’ отсутствует в IMySuperInterface
  • ни то, ни другое: извините, но вход в систему несовместим с типом ‘Type’

Я потерялся: (.. Как я могу определить в качестве параметра моей функции класс, который реализует мой интерфейс? Примечание: аргумент в конструкторе моего класса постоянно меняется, а также аргумент функции в интерфейсе.

Комментарии:

1. Мне трудно понять, чего вы пытаетесь достичь здесь. Где handle на самом деле вызывается и какие аргументы вы ему передаете? Наличие необязательного аргумента в interface почти наверняка не то, что вы хотите, поскольку это означает, что реализации не могут требовать никаких аргументов. Либо аргументы определены и известны, либо handle это функция, которая не принимает аргументов.

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

3. @LindaPaiste спасибо за ваш комментарий, я добавляю функцию дескриптора в класс. Я понимаю ваше предупреждение о необязательных аргументах в интерфейсе, но я не могу четко предсказать входящий элемент здесь.

4. @JayMcDoniel На самом деле вы можете ограничить область применения декоратора, изменив тип целевых параметров в определении декоратора

Ответ №1:

Сегодня я узнал, что можно вводить декоратор для определенных классов. В любом случае, я смог реализовать что-то подобное, подобное этому:

 export function Command(
  options: CommandMetadata,
): <TFunction extends CommandRunner>(target: TFunction) => void | TFunction {
  return (target) => {
    Reflect.defineMetadata(CommandMeta, options, target);
    return target;
  };
}
 

Это полностью типизированный декоратор, вместо того, чтобы использовать ClassDecorator тип, чтобы я мог правильно установить target общий тип. Должно быть примерно то, что вы ищете. Просто CommandRunner замените свой интерфейс и возврат функции anon target логикой вашего декоратора.

Комментарии:

1. Ты убийца, ответ правильный, но для меня он был полностью хорош, вот ответ: export function Feature<K extends string>( key: K, ): <TFunction extends Class<IFeature>>( target: TFunction, ) => void | TFunction { return (target) => { Feature.cache.set(key, target); return target; }; } с помощью class = export type Class<T = unknown, Arguments extends any[] = any[]> = new ( ...arguments_: Arguments ) => T;