Reputation: 222344
I'm trying to make foo
generic decorator to conform MethodDecorator
type:
const foo: MethodDecorator = function <T extends Function = Function>(
target: object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>
): TypedPropertyDescriptor<T> {
return {
configurable: true,
enumerable: false,
value: descriptor.value!.bind(null)
};
}
foo
may be used directly as helper function, I would prefer to have an option to additionally type it as a generic.
Here is the error:
Type '<T extends Function = Function>(target: object, propertyKey: string | symbol, descriptor: TypedPr...' is not assignable to type 'MethodDecorator'.
Types of parameters 'descriptor' and 'descriptor' are incompatible.
Type 'TypedPropertyDescriptor<T>' is not assignable to type 'TypedPropertyDescriptor<Function>'.
Types of property 'value' are incompatible.
Type 'T | undefined' is not assignable to type 'Function | undefined'.
Type 'T' is not assignable to type 'Function | undefined'.
Type 'T' is not assignable to type 'Function'.
How can foo
conform MethodDecorator
?
Upvotes: 2
Views: 2638
Reputation: 4266
Seems like MethodDecorator
is not a generic type alias, so T
type cannot be narrowed.
type Foo<T> = (x: T) => T; // this one is generic
type Bar = (x: T) => T; // and this is not
Which make sense, since the assumptions that are made in foo
(i.e. descriptor.value
has a bind
property) are not true for MethodDecorator
in general.
Since type
is a mere alias, we can define our own.
type TypedMethodDecorator = <T extends Function>(
target: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void;
const foo: TypedMethodDecorator = function (target, propertyKey, descriptor) {
return {
configurable: true,
enumerable: false,
value: descriptor.value!.bind(null)
};
}
class C {
@foo
m() {
console.log('this:', this);
}
}
new C().m(); // 'this: null'
Due to type inference the compiler understands that foo
is a valid decorator.
Upvotes: 1