Reputation:
There is a project that implements Java(FX) API in TypeScript/JavaScript (Script4J). And now I want to modify Comparator functional interface. This is default solution:
export interface Comparator<T> {
(o1: T, o2: T): number;
}
Such solution allows to add comparators as arrow functions (like java lambda), for example:
let comparator: Comparator<number> = (n1: number, n2: number): number => {
return n1 - n2;
};
let treeMap: SortedMap<number, string> = new TreeMap<number, string>(comparator);
As you see the code is very clean. Now I need to add to TypeScript Comparator interface next method (Java code):
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
What is the best way to do it, taking into consideration that I can't change API?
Upvotes: 3
Views: 1472
Reputation:
After some thinking I decided the only way to reach maximum Java API is to use abstract classes instead of interfaces. This is my solution:
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
if (name !== 'constructor') {
derivedCtor.prototype[name] = baseCtor.prototype[name];
}
});
});
}
type ComparatorFunc<T> = (o1: T, o2: T) => any;
abstract class Comparator<T> {
public static lambda<T>(func: ComparatorFunc<T>): Comparator<T> {
return new class extends Comparator<T> {
public compare(o1: T, o2: T): number {
return func(o1, o2);
}
}
}
public abstract compare(o1: T, o2: T): number;
}
//VAR 1 - lambda
let lambdaComparator: Comparator<number> = Comparator.lambda((n1: number, n2: number) => { return n1 - n2;});
console.log("Lambda comparator");
console.log(lambdaComparator.compare(100, 50));
//VAR 2 - full implementation
class MyComparator implements Comparator<number> {
public compare(o1: number, o2: number): number {
return o1 - o2;
}
}
applyMixins (MyComparator, [Comparator]);
let classComparator: MyComparator = new MyComparator();
console.log("Class comparator");
console.log(classComparator.compare(100, 50));
Advantages:
Disadvantages:
Upvotes: 1
Reputation: 250106
There is no direct equivalent to default interface method implementations in typescript. You can us ea function that assigns the default to a comparator function:
export interface Comparator<T> {
(o1: T, o2: T): number;
reversed() : any // not sure what return type should be, maybe (o1: T, o2: T) => number ?
}
function comparatorWithDefault<T>(fn: (o1: T, o2: T) => number) {
function reversed(this: Comparator<T>) {
return Collections.reverseOrder(this);
}
return Object.assign(fn, { reversed });
}
let comparator: Comparator<number> = comparatorWithDefault((n1: number, n2: number): number => {
return n1 - n2;
})
let treeMap: SortedMap<number, string> = new TreeMap<number, string>(comparator);
Unlike the Java adding the member to Comparator
will break a lot of existing code.
Upvotes: 0