angular - Eine Komponente mit generischem Typ deklarieren
Ist es möglich, eine Komponente mit einem generischen Typ in Angular 4 zu deklarieren?
Der folgende Code verursacht Build-Fehler:
export class MyGenericComponent<T> implements OnInit {
@Input() data: BehaviorSubject<T[]>;
//...
}
Der Fehler beim Ausführen von ng serve ist:
ERROR in C:/.../my-generic.module.ts (5,10): Module '"C:/.../my-generic.component"' has no exported member 'MyGenericComponent'.
Beispiel:
Das folgende Beispiel ist ein Versuch, eine generische Datentabelle zu implementieren, bei der @Input() data von einer Komponente, die diese Komponente aufruft, zu einer anderen wechselt. Die Frage ist, ob BehaviorSubject<any[]> zu BehaviorSubject<T[]> geändert werden könnte, wobei T der generische Typ wäre, der an die Komponente übergeben wird?
@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() {}
}
Antwort #1
Sie können auch über das ViewChild auf den Type-Parameter wie folgt zugreifen:
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);
}
}
Antwort #2
Sie können es deklarieren, aber nicht direkt verwenden. Sie können so etwas tun:
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(); }
}
