I'm trying to add types to a function that takes a list of method names, the original object that may contain or not contain a method from the list, and the fallback object that also can include or not include a method from the list.
The function follows the algorithm for each method in the method list:
- If the method exists in the original object, it is added to the result object.
- If a method exists in the fallback object, it is added to the result object.
- If nothing above exists, the no-op method (empty function) is added to the result object.
I wrote the following code, but it has errors in both code and returns value:
type Reflection<
PropertyName extends PropertyKey,
ReflectingObject extends Partial<Record<PropertyName, Function>>,
FallbackObject extends Record<PropertyName, Function>
> = {
[Prop in PropertyName]: ReflectingObject[Prop] extends never
? FallbackObject[Prop] extends never
? () => void
: FallbackObject[Prop]
: ReflectingObject[Prop];
};
const noop = () => { }
const reflectMethods = <
PropertyName extends PropertyKey,
ReflectingObject extends Partial<Record<PropertyName, Function>>,
FallbackObject extends Record<PropertyName, Function>
>(
reflectingObject: Partial<ReflectingObject>,
methodNames: PropertyName[],
fallbacks: Partial<FallbackObject> = {},
): Reflection<PropertyName, ReflectingObject, FallbackObject> =>
methodNames.reduce<
Reflection<PropertyName, ReflectingObject, FallbackObject>
>((reflection, name) => {
reflection[name] = reflectingObject[name] ?? fallbacks[name] ?? noop; // here the code fails with T2322
return reflection;
}, {} as Reflection<PropertyName, ReflectingObject, FallbackObject>);
Also, if I use this function, it will fail if I do not mention any of the methods in the original object or the fallback object though it should have the () => void type.
class A {
a(aa: number) {
return aa;
}
b(bb: string) {
return bb;
}
c() {}
}
const proto = A.prototype;
const aaaa = reflectMethods(proto, ['a', 'c', 'd'], { a(aa: number) { return aa + 2 } });
aaaa.a(11);
aaaa.d(); // here it fails with T2571
I probably misused the conditional types somehow here, but I'm not sure how to fix them to make them work.
Here is the link to the Typescript playground that demonstrates the issue.