Рассмотрим следующий код. ColumnSorter предназначен для инкапсуляции набора функций сортировки по их строковым именам, а затем применения правильной функции сортировки к массиву.
export class ColumnSorter<T> {
constructor(private map: Map<string, (a: T, b: T) => number>) {
}
public sortBy<T>(sortcol: string, items: T[]): void {
// *** DOES NOT COMPILE:
items.sort(this.map.get(sortcol));
// *** DOES NOT COMPILE EITHER:
let fn: (a: T, b: T) => number = this.map.get(sortcol);
}
}
// here is an example Quote arrays. Others could be position, account, etc.
// implementing with sort functions for that type.
const quoteFunctionMap: Map<string, (a: Quote, b: Quote) => number> = new Map([
['byLastPrice', (q1: Quote, q2: Quote) => {
return q1.lastPrice - q2.lastPrice;
}],
['bySymbol', (q1: Quote, q2: Quote) => {
return q1.symbol.localeCompare(q2.symbol);
}]
]);
let colsort = new ColumnSorter<Quote>(quoteFunctionMap);
let quotes: Quote[] = [new Quote(), new Quote()]; // blank quotes, for compile test
colsort.sortBy("byLastPrice", quotes);
Проблема заключается в извлечении функции сортировки из карты. Сообщение об ошибке подробное, но мне недостаточно, чтобы найти корень проблемы. Чего-то не хватает в моем коде?
Argument of type '((a: T, b: T) => number) | undefined' is not assignable to parameter of type '((a: T, b: T) => number) | undefined'.
Type '(a: T, b: T) => number' is not assignable to type '(a: T, b: T) => number'. Two different types with this name exist, but they are unrelated.
Types of parameters 'a' and 'a' are incompatible.
Type 'T' is not assignable to type 'T'. Two different types with this name exist, but they are unrelated.
'T' could be instantiated with an arbitrary type which could be unrelated to 'T'.ts(2345)
@pink просто считайте, что это простой объект данных, где символ — это строка, а lastPrice — это число.






Ваш метод ColumnSorter.sortBy должен использовать общий T из класса, а не определять свой собственный.
export class ColumnSorter<T> {
constructor(private map: Map<string, (a: T, b: T) => number>) {
}
// NOTE: changed from sortBy<T> to just sortBy below!
public sortBy(sortcol: string, items: T[]): void {
items.sort(this.map.get(sortcol));
let fn = this.map.get(sortcol);
if (!fn) {
throw new Error(`No sorter exists for ${sortcol}`);
}
// ...
}
}
Спасибо, я думал это просто! Но для моего полного понимания, почему вторая строка (пусть fn...) все еще не компилируется? Используя ваше определение класса, я получаю Type '((a: T, b: T) => number) | undefined' is not assignable to type '(a: T, b: T) => number'.⏎ Type 'undefined' is not assignable to type '(a: T, b: T) => number'.
Это потому, что map.get может возвращать значение undefined. Поэтому вам нужно будет выдать ошибку, если функция не может быть найдена с помощью sortcol на карте или что-то в этом роде.
Обновлен мой ответ, чтобы включить эту логику.
Да, карта может возвращать значение undefined, но я включил это в ссылочный тип. Вы можете удалить тип и заставить его компилироваться (что вы и сделали, проверка экземпляра не требуется), но теперь это не тот же тип, а просто ссылка на любой тип. Я поэкспериментировал с этим и обнаружил, что проблема в том, что number | undefined интерпретируется компилятором как возвращаемый тип функции, а не как альтернативный возвращаемый тип. Заключив его в круглые скобки, он компилируется: let fn: ((a: T, b: T) => number) | undefined
Аннотация типа на самом деле не нужна, Typescript уже правильно выводит ее как ((a: T, b: T) => number) | undefined — вы можете увидеть это, наведя курсор на fn здесь -> tsplay.dev/m3BLkN
Что такое класс Quote (нам нужны определения)?