web-dev-qa-db-fra.com

La propriété dans le type n'est pas assignable à la même propriété dans le type de base

Bonjour j'ai un exemple de base où je continue à obtenir cette erreur et je ne suis pas sûr de ce que c'est exactement le problème.

Fondamentalement, je veux transmettre différents types à class A Au moment de l'exécution. Dans l'exemple donné, c'est Order mais je vais écrire d'autres classes pour Product, Customers et plus et pour tous, je veux utiliser A<T> Comme parent . J'ai également ajouté le code réel en dessous de l'exemple minimal.

Peut plaire à quelqu'un d'expliquer la solution et le problème à cela.

interface Order{
    customer: {
        name: string;
    };
}

abstract class A<T>{
    protected abstract matches<T>(tableData: T, term: string): boolean;
}

class B extends A<Order>{

    protected matches<T extends Order>(tableData: T, term: string): boolean {
        return tableData.customer.name.toLowerCase().includes(term.toLowerCase());
    }
}

L'objectif est d'accéder à tableData.customer Dans class B. Je veux passer Order à la méthode matches comme type générique, mais je ne sais pas comment cela peut être mis en œuvre correctement.

Mise à jour

Classe des parents:

export abstract class TableFilterService<T> {
  private _loading$ = new BehaviorSubject<boolean>(true);
  private _search$ = new Subject<void>();
  private _total$ = new BehaviorSubject<number>(0);
  private _tableData$: BehaviorSubject<T[]> = new BehaviorSubject([]);
  private _data$!: T[];

  protected _state: State = {
    page: 1,
    pageSize: 50,
    searchTerm: '',
    sortColumn: '',
    sortDirection: ''
  };

  private compare = (v1: string | number, v2: string | number) => v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
  protected abstract matches<T>(tableData: T, term: string, pipe: PipeTransform): boolean;

  get tableData$() { return this._tableData$.asObservable(); }
  get search$() { return this._search$.asObservable(); }
  get total$() { return this._total$.asObservable(); }
  get loading$() { return this._loading$.asObservable(); }
  get page() { return this._state.page; }
  get pageSize() { return this._state.pageSize; }
  get searchTerm() { return this._state.searchTerm; }
  get data() { return this._data$; }

  set data(data: T[]) { this._data$ = data; }
  set page(page: number) { this._set({page}); }
  set pageSize(pageSize: number) { this._set({pageSize}); }
  set searchTerm(searchTerm: string) { this._set({searchTerm}); }
  set sortColumn(sortColumn: SortColumn) { this._set({sortColumn}); }
  set sortDirection(sortDirection: SortDirection) { this._set({sortDirection}); }

  constructor(protected pipe: DecimalPipe) {

    this._search$.pipe(
      tap(() => this._loading$.next(true)),
      debounceTime(200),
      switchMap(() => this._search()),
      delay(200),
      tap(() => this._loading$.next(false))
    ).subscribe(result => {
      this._tableData$.next(result.tableData);
      this._total$.next(result.total);
    });

    this._search$.next();
  }

  protected sort<T>(orders: T[], column: SortColumn, direction: string): T[] {
    if (direction === '' || column === '') {
      return orders;
    } else {
      return [...orders].sort((a: any, b: any) => {
        const res = this.compare(a[column], b[column]);
        return direction === 'asc' ? res : -res;
      });
    }
  }

  protected _search(): Observable<SearchResult<T>> {
    const {sortColumn, sortDirection, pageSize, page, searchTerm} = this._state;

    // 1. sort
    let tableData = this.sort(this.data, sortColumn, sortDirection);

    // 2. filter
    tableData = tableData.filter(data => this.matches(data, searchTerm, this.pipe));
    const total = tableData.length;

    // 3. paginate
    tableData = tableData.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);

    return of({ tableData, total});
  }

  private _set(patch: Partial<State>) {
    Object.assign(this._state, patch);
    this._search$.next();
  }
}

Classe enfant:

export class OrderTableService extends TableFilterService<Order>{

  protected matches(tableData: Order, term: string, pipe: PipeTransform): boolean {
    return tableData.customer.name.toLowerCase().includes(term.toLowerCase());
  }
}

Erreur:

enter image description here

l'erreur complète:

Property 'matches' in type 'OrderTableService' is not assignable to the same property in base type 'TableFilterService<Order>'. Type '(tableData: Order, term: string, pipe: PipeTransform) => boolean' is not assignable to type '<T>(tableData: T, term: string, pipe: PipeTransform) => boolean'. Types of parameters 'tableData' and 'tableData' are incompatible. Type 'T' is not assignable to type 'Order'.ts

3
Mj1992

Votre fonction abstrait générique matches<T> remplace générique T de la classe A<T>. Ce que vous avez écrit, c'est fondamentalement ceci:

abstract class A<T>{
    protected abstract matches<U>(tableData: U, term: string): boolean;
}

Le générique T au sommet de la classe était fondamentalement inutile. La solution pourrait ressembler Ceci :

interface Order{
    customer: {
        name: string;
    };
}

abstract class A<T>{
    // No generic <T> at the function itself anymore. Now tableData: T refers to A<T>
    protected abstract matches(tableData: T, term: string): boolean;
}

class B extends A<Order>{

    protected matches(tableData: Order, term: string): boolean {
        return tableData.customer.name.toLowerCase().includes(term.toLowerCase());
    }
}

class C extends A<Order>{

    protected matches<T extends Order>(tableData: T, term: string): boolean {
        return tableData.customer.name.toLowerCase().includes(term.toLowerCase());
    }
}
2
Mirco S.