Skip to content

support decorators altering return type of methodΒ #7349

@opensrcken

Description

@opensrcken

TypeScript Version:

nightly (1.9.0-dev.20160217)

Code

function wrap<T, U>(wrapper: (arg: T) => U) {
    return function(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => T>) {
        var originalMethod = descriptor.value; // save a reference to the original method

        // NOTE: Do not use arrow syntax here. Use a function expression in
        // order to use the correct value of `this` in this method (see notes below)
        const newDescriptor = {
            value: function(...args: any[]) {
                console.log("The method args are: " + JSON.stringify(args)); // pre
                var result = wrapper(<T> originalMethod.apply(this, args));               // run and store the result
                console.log("The return value is: " + result);               // post
                return result;                                               // return the result of the original method
            }
        };

        return newDescriptor;
    }
}

function len(val: string): number {
    return val.length;
}

class MyClass {
    @wrap<string, number>(len)
    myMethod(arg: string) {
        return "Message -- " + arg;
    }
}

const t: number = new MyClass().myMethod("testing");

Expected behavior:
I expect this to compile, and modify the return type of MyClass#myMethod.

Actual behavior:

tsc decorators-broken.ts --experimentalDecorators --target es5
decorators-broken.ts(25,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
  Type '{ value: (...args: any[]) => number; }' is not assignable to type 'void'.
decorators-broken.ts(31,7): error TS2322: Type 'string' is not assignable to type 'number'.

I'm trying to create a decorator that wraps methods, potentially altering the wrapped method's return type, making function composition possible through decoration. I initially thought this was a bug, but upon inspecting MethodDecorator's type signature, this is probably intentional:

type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void;

Can we add something like the following?

type MutatingMethodDecorator = <T, U>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<U> | void;

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions