Consider the following types:
type objectExtensionFunction<TBaseObject extends object, TExtendWith extends object> = (base: TBaseObject) => TExtendWith & TBaseObject;
declare function myEndpoint<TObjects extends objectExtensionFunction<any, any>>(objects: TObjects): any;
The above function accepts any array of objectExtensionFunction
types. These are functions, that will receive a base object, and should add an additional property to that object, and create a new object type, based on the property added.
What I would want to achieve, is somehow tell myEndpoint
function, that the minimal input array, should contain functions, that will at least add some specific properties to the first base object supplied, if all of the functions are called on a base object.
In other words:
/**
* how could I declare `myEndPoint` function, that it will only accept an array of
* `objectExtensionFunction` types, if the merging of all the function results of those
* `objectExtensionFunction` types extends my supplied base type
*/
declare function myEndPoint(): any;
A concrete example to illustrate the problem I am trying to solve:
type requiredEndType = {
a: boolean,
b: boolean
}
type objectExtensionFunction<TBaseObject extends object, TExtendWith extends object> = (base: TBaseObject) => TExtendWith & TBaseObject;
const addToBaseA: objectExtensionFunction<{}, {
a: boolean
}> = (base) => {
return {
...base,
a: true
};
}
const addToBaseB: objectExtensionFunction<{}, {
b: boolean
}> = (base) => {
return {
...base,
b: true
};
}
const addToBaseC: objectExtensionFunction<{}, {
c: boolean
}> = (base) => {
return {
...base,
c: true
};
}
/** I am looking to type this function, so that it will accept an array of `objectExtensionFunction` types
* that when called in succession, chained, providing an empty object as the first object parameter, will resolve
* in an object, that satisfies the `requiredEndType` constraint
*/
declare function myEndpoint<TObjects extends objectExtensionFunction<any, any>[]>(objects: TObjects): void;
myEndpoint([addToBaseA, addToBaseB]); // this should be accepted
myEndpoint([addToBaseA, addToBaseB, addToBaseC]); // this also should be accepted
myEndpoint([addToBaseB, addToBaseA]); // this also should be accepted, the order does not matter
myEndpoint([addToBaseA, addToBaseC]); // this should raise an error, after running all the functions, the `b` property would be missing
Here's a typescript playground link of the above code.