You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript组件中实现泛型类以复用列表选择组件?

实现Angular泛型选择列表组件(app-select-item)

可行性结论

完全可行,TypeScript的泛型机制结合Angular的组件输入输出体系,能够完美实现类似C#泛型类的复用效果,完全覆盖你提到的需求场景。

实现步骤与代码示例

1. 定义泛型组件类

创建app-select-item组件,通过<T>声明泛型类型,将输入、输出及API函数都绑定到该类型:

import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, filter } from 'rxjs/operators';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-select-item',
  templateUrl: './select-item.component.html',
  styleUrls: ['./select-item.component.css']
})
export class SelectItemComponent<T> implements OnInit {
  // 初始选中项
  @Input() initialSelected: T | null = null;
  // 获取数据列表的API函数,支持传入搜索关键词,返回Observable<T[]>
  @Input() apiFunc: (searchTerm?: string) => Observable<T[]>;
  // 可选:指定列表项显示的字段(比如Customer的name,Contract的contractNumber)
  @Input() displayField: keyof T = 'name' as keyof T;
  
  // 选中项输出事件
  @Output() select = new EventEmitter<T>();

  // 搜索控件
  searchControl = new FormControl('');
  // 数据列表(Observable形式,配合async管道渲染)
  items$: Observable<T[]>;
  // 当前选中项
  selectedItem: T | null = null;

  ngOnInit(): void {
    this.selectedItem = this.initialSelected;
    
    // 实现带防抖的搜索筛选逻辑
    this.items$ = this.searchControl.valueChanges.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      filter(term => term.length >= 0), // 允许空搜索加载全部数据
      switchMap(term => this.apiFunc(term))
    );
  }

  // 选中项处理逻辑
  onSelect(item: T): void {
    this.selectedItem = item;
    this.select.emit(item);
  }
}

2. 组件模板(select-item.component.html)

模板中通过displayField动态绑定泛型对象的显示字段,适配不同模型的渲染需求:

<div class="search-bar">
  <input type="text" [formControl]="searchControl" placeholder="输入关键词搜索..." />
</div>

<ul class="item-list">
  <li 
    *ngFor="let item of items$ | async"
    [class.active]="selectedItem === item"
    (click)="onSelect(item)"
  >
    {{ item[displayField] }}
  </li>
</ul>

3. 父组件中使用泛型组件

在父组件模板中,直接传入对应模型的API函数、初始选中项及显示字段,TypeScript会自动推断泛型类型:

<!-- 客户选择组件 -->
<app-select-item
  [initialSelected]="currentCustomer"
  [apiFunc]="customerApi.getCustomers"
  [displayField]="'name'"
  (select)="handleCustomerSelect($event)"
></app-select-item>

<!-- 合同选择组件 -->
<app-select-item
  [initialSelected]="currentContract"
  [apiFunc]="contractApi.getContracts"
  [displayField]="'contractNumber'"
  (select)="handleContractSelect($event)"
></app-select-item>

父组件TypeScript示例:

import { Component } from '@angular/core';
import { Customer } from './models/customer.model';
import { Contract } from './models/contract.model';
import { CustomerApiService } from './services/customer-api.service';
import { ContractApiService } from './services/contract-api.service';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html'
})
export class ParentComponent {
  currentCustomer: Customer | null = null;
  currentContract: Contract | null = null;

  constructor(
    private customerApi: CustomerApiService,
    private contractApi: ContractApiService
  ) {}

  handleCustomerSelect(customer: Customer): void {
    this.currentCustomer = customer;
    // 后续业务逻辑处理
  }

  handleContractSelect(contract: Contract): void {
    this.currentContract = contract;
    // 后续业务逻辑处理
  }
}

4. 补充说明

  • 如果需要基于模型类做实例化操作(比如创建空对象),可以添加@Input() modelClass: new () => T;,通过new this.modelClass()生成实例。
  • 泛型类型T支持显式声明(如<app-select-item<Customer>>),但通常父组件传入对应API后TypeScript会自动推断,无需额外配置。

内容的提问来源于stack exchange,提问作者Freek Wiekmeijer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:15:11