Imagine I have the following:
const upsert = curry(function upsert(predicate, resolver, item, data) {
const index = findIndex(predicate, data);
return index < 0 ? append(item, data) : adjust(index, resolver(item), item, data);
});
I defined the types as follows for this function:
type Predicate<T> = (item: T) => boolean;
interface Reconciliation<T = unknown> {
<L extends object>(left: L): <R extends object>(right: R) => T;
<L extends object, R extends object>(left: L, right: R): T;
}
interface Upsert {
<T extends object>(predicate: Predicate<T>): (reconciliation: Reconciliation<T>, item: T, data: readonly T[]) => T[];
<T extends object>(predicate: Predicate<T>, reconciliation: Reconciliation<T>): (item: T, data: readonly T[]) => T[];
<T extends object>(predicate: Predicate<T>, reconciliation: Reconciliation<T>, item: T): (data: readonly T[]) => T[];
<T extends object>(predicate: Predicate<T>, reconciliation: Reconciliation<T>, item: T, data: readonly T[]): T[];
}
const upsert = curry(function upsert<T>(predicate: Predicate<T>, resolver: Reconciliation<T>, item: T, data: readonly T[]) {
const index = findIndex(predicate, data);
return index < 0 ? append(item, data) : adjust(index, resolver(item), item, data);
}) as Upsert;
However, I don't really want to do this every single time I make a function like this... is there a better way to do something like this?