If you want your decorator factory to be non-generic and produce a generic decorator, you'll need to make some changes. Currently, your decorator factory is generic, returning a non-generic decorator. Here's the distinction between the two scenarios:
// Incorrect
declare const genericFactoryForSpecificFunction: <T>() => (x: T) => T;
const oops = genericFactoryForSpecificFunction()(123); // unknown
// Correct
declare const specificFactoryForGenericFunction: () => <T>(x: T) => T;
const okay = specificFactoryForGenericFunction()(123); // 123
In the incorrect case, the compiler has trouble inferring T
as there's no value of type T
available in the expression where
genericFactoryForSpecificFunction()
is called. This results in an inferred type of
unknown
, leading to the return value also being
unknown
. In the correct case, inference happens at the call to the function returned by
specificFactoryForGenericFunction()
, allowing the compiler to use a value of type
T
for inference, resulting in
123
as output.
Once you implement this change, the Decorator
type needs to represent a specific type that denotes a generic function call signature. You can achieve this using multi-call-signature overloads:
type Decorator = {
<T extends new (...args: any) => any>(ctor: T): T;
<T, K extends keyof T>(proto: T, member: K): void;
}
declare const d: Decorator;
d(RegExp); // okay, class decorator
d({ a: "" }, "a") // okay, prop decorator
d(RegExp, "oops"); // error, cannot pass prop to class decorator
Your updated example code will then look like this:
function Schema(): Decorator {
return (target: any, propertyKey?: string) => {
if (target instanceof Function) {
return target;
}
return;
};
}
@Schema()
export default class MyClass {
@Schema()
bool: boolean = false;
}
Everything seems to be in order now.
Hope this explanation helps. Best of luck with your implementation!
Access the playground link here