声明具有泛型类型的组件

Str*_*der 26 typescript typescript-generics angular-components angular

是否可以在Angular 4中声明具有泛型类型的组件?

以下代码导致生成错误:

export class MyGenericComponent<T> implements OnInit {
    @Input()  data: BehaviorSubject<T[]>;

    //...
}
Run Code Online (Sandbox Code Playgroud)

执行时的错误ng serve是:

ERROR in C:/.../my-generic.module.ts (5,10): Module '"C:/.../my-generic.component"' has no exported member 'MyGenericComponent'.
Run Code Online (Sandbox Code Playgroud)

例:

以下示例是尝试实现通用数据表,其中@Input() data从一个组件"调用此组件"到另一个组件的更改.现在的问题是可以BehaviorSubject<any[]>被改变到BehaviorSubject<T[]>哪里T会是泛型类型传递到组件?

@Component({
  selector: 'my-data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.css']
})
export class DataListComponent implements OnInit {
  @Input()  data: BehaviorSubject<any[]>;
  @Output() onLoaded = new EventEmitter<boolean>();

  private tableDataBase : TableDataBase = new TableDataBase();
  private dataSource : TableDataSource | null;

  constructor() { }

  ngOnInit() {
    this.tableDataBase.dataChange = this.data;
    this.dataSource = new TableDataSource(this.tableDataBase);
    this.onLoaded.emit(true);
  }
}

class TableDataBase {
  dataChange: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([]);

  get data(): any[] {
    return this.dataChange.value;
  }
}

class TableDataSource extends DataSource<any> {

  constructor(private tableDataBase: TableDataBase) {
    super();
  }

  connect(): Observable<any[]> {
    return Observable.of(this.tableDataBase.data);
  }

  disconnect() {}
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*ger 15

您还可以通过ViewChild访问Type参数,如下所示:

export class Bazz {
  name: string;

  constructor(name: string) {
    this.name = name;   
  }
}

@Component({
  selector: 'app-foo',
  template: `<div>{{bazz?.name}}</div>`,
  exportAs: 'appFoo'
})
export class FooComponent<T> {
  constructor() {}
  private _bazz: T;

  set bazz(b: T) {
    this._bazz = b;
  }

  get bazz(): T {
   return this._bazz;
  }
}

@Component({
  selector: 'app-bar',
  template: `<app-foo #appFoo></app-foo>`,
  styleUrls: ['./foo.component.scss'],
})
export class BarComponent<T> implements OnInit {
  @ViewChild('appFoo') appFoo: FooComponent<Bazz>;

  constructor() {}

  ngOnInit() {
    this.appFoo.bazz = new Bazz('bizzle');
    console.log(this.appFoo.bazz);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,Angular 足够聪明,可以从输入中找出“T”。假设您的通用组件中有“Input() data: T”。当您使用该组件并分配 `[data]="someTypedDataVariable"` 时,角度编译器将使用 `someTypedDataVariable` 的类型来实例化通用组件。这就是角度材料表(基于 cdk 表)的工作原理。与 Angular 语言服务相结合,还将为您提供类型安全 + typeahead iniside mat-table 列定义。供参考:https://github.com/angular/components/blob/master/src/cdk/table/table.ts (12认同)
  • 那么如何使用“BarComponent”的“T”类型参数呢?目前还不清楚当实例化“BarComponent”时您期望收到什么作为参数?当您控制其实例化时,使用通用具体类是有意义的(这样您就可以控制要传递的参数)。但在组件的情况下 - 角度框架本身实例化它 - 并且框架不知道你的参数,并且无法传递有意义的东西 (3认同)

Sas*_*sxa 7

您可以声明它,但不能直接使用它.你可以这样做:

export abstract class Form<T> implements OnInit, OnChanges {
  someMethod() { throw 'Dont use directly' }
  otherMethod() { return 'Works!'; }
  // Note that below will cause compilation error
  //   TypeError: Object prototype may only be an Object or null: undefined
  // You cannot use protected in this usecase
  protected anotherMethod() { }
}

@Component({})
export class ModelOneForm extends Form<ModelOne> {
  someMethod() { return this.otherMethod(); }
}
Run Code Online (Sandbox Code Playgroud)