Как сделать компонент Angular более универсальным, чтобы он мог принимать несколько типов данных в качестве @Input?

У меня есть компонент, который извлекает данные из серверной части, отображает их в таблице и позволяет пользователю сделать выбор. Весь компонент основан на типе извлекаемых данных, поэтому он строго ограничен этим типом (Элемент). Теперь мне нужен компонент для работы с немного другими типами данных на основе @Input. Я не знаю, как заставить его работать с Typescript.

Упрощенный компонент выглядит так:

export class MyComponent implements OnInit {
@Input() public selectedItems: Item[] = [];
@Output() public validateButtonEmitter = new EventEmitter<Item[]>();
@Output() public cancelButtonEmitter = new EventEmitter<Item[]>();

constructor(private readonly facade: Facade) {}

public ngOnInit(): void {
    this.facade.setInitialSelectedItems(this.selectedItems);
    this.facade.getDataFromBackend();
}

public validateButtonHandler(selectedItems: Item[]): void {
    this.validateButtonEmitter.emit(selectedItems);
}

public cancelButtonHandler(selectedItems: Item[]): void {
    this.cancelButtonEmitter.emit(selectedItems);
}

}

Мой план состоит в том, чтобы добавить параметр @Input для передачи нужных данных для извлечения. затем я модифицирую метод getDataFromBackend(), чтобы он принимал аргумент, позволяя динамически выбирать маршрут на основе входных данных. Однако я не уверен, как провести рефакторинг всех методов внутри компонента, чтобы они были более общими в отношении типов данных.

Любые рекомендации будут очень признательны!

это все Item, но вы можете прочитать TypeGuards и сужение

user3791775 11.05.2024 01:26

@user3791775 user3791775 Спасибо за подсказку. Однако правильно ли я понимаю, что защита типов требует от меня указания всех возможных типов в каждом методе?

Ryley38 12.05.2024 00:01
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
90
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

компоненты могут быть универсальными. например, код в вопросе будет выглядеть так

// generic could be restrictive. for example TItem extends {selected: boolean}
// will make sure that items passed have a selected field
export class MyComponent<TItem> implements OnInit { 
@Input() public selectedItems: TItem[] = [];
@Output() public validateButtonEmitter = new EventEmitter<TItem[]>();
@Output() public cancelButtonEmitter = new EventEmitter<TItem[]>();

constructor(private readonly facade: Facade<TItem>) {} // most probably you want your facade to be generic as well

public ngOnInit(): void {
    this.facade.setInitialSelectedItems(this.selectedItems);
    this.facade.getDataFromBackend();
}

public validateButtonHandler(selectedItems: TItem[]): void {
    this.validateButtonEmitter.emit(selectedItems);
}

public cancelButtonHandler(selectedItems: TItem[]): void {
    this.cancelButtonEmitter.emit(selectedItems);
}

Спасибо за Ваш ответ. Как именно должен работать этот <TItem>? Я не знаком с этим

Ryley38 11.05.2024 10:19

если вы привязываетесь к массиву чисел компонента [seleccted] = "nums", то все остальное общее (в данном случае 2 выхода) будет иметь один и тот же тип TItem — они будут выдавать числа. это похоже на машинописную функцию с общими аргументами и типом возвращаемого значения

Andrei 11.05.2024 10:23

Значит, мне следует сделать настенную библиотеку универсальной, включая магазин? Этот компонент является небольшой частью библиотеки.

Ryley38 12.05.2024 10:41

зависит от того, как спроектирован API библиотеки. если вы делаете http-запросы внутри библиотеки - тогда да

Andrei 12.05.2024 11:51

Вы можете использовать концепцию базового компонента и расширить ее с помощью любого типа ввода, который вы передаете в T.

export abstract class MyComponentBase<T> implements OnInit {
@Input() public selectedItems: T[] = [];
@Output() public validateButtonEmitter = new EventEmitter<T[]>();
@Output() public cancelButtonEmitter = new EventEmitter<T[]>();

constructor(private readonly facade: Facade) {}

public ngOnInit(): void {
    this.facade.setInitialSelectedItems(this.selectedItems);
    this.facade.getDataFromBackend();
}

public validateButtonHandler(selectedItems: T[]): void {
    this.validateButtonEmitter.emit(selectedItems);
}

public cancelButtonHandler(selectedItems: T[]): void {
    this.cancelButtonEmitter.emit(selectedItems);
}

// Расширяем компоненты разного типа, например

export class MyComponentChild1 extends MyComponentBase<string>{}

export class MyComponentChild2 extends MyComponentBase<Item>{}

export class MyComponentChild3 extends MyComponentBase<'any-custom-type'>{}

Для этого вам может потребоваться изменить класс фасада на универсальный или заставить метод setInitialSelectedItems принимать предварительно определенные типы, которые могут вам понадобиться.

public setInitialSelectedItems(data: string | Item | 'any-custom-type') { }

Другие вопросы по теме