<p dir="auto"><strong>TypeScript Version:</strong></p>
<p dir="auto">nightly (1.9.0-dev.20160217)</p>
<p dir="auto"><strong>Code</strong></p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function wrap&lt;T, U&gt;(wrapper: (arg: T) =&gt; U) {
    return function(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor&lt;(...args: any[]) =&gt; T&gt;) {
        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(&quot;The method args are: &quot; + JSON.stringify(args)); // pre
                var result = wrapper(&lt;T&gt; originalMethod.apply(this, args));               // run and store the result
                console.log(&quot;The return value is: &quot; + result);               // post
                return result;                                               // return the result of the original method
            }
        };

        return newDescriptor;
    }
}

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

class MyClass {
    @wrap&lt;string, number&gt;(len)
    myMethod(arg: string) {
        return &quot;Message -- &quot; + arg;
    }
}

const t: number = new MyClass().myMethod(&quot;testing&quot;);"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">wrap</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-kos">,</span> <span class="pl-smi">U</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">wrapper</span>: <span class="pl-kos">(</span><span class="pl-s1">arg</span>: <span class="pl-smi">T</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">U</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-s1">target</span>: <span class="pl-smi">Object</span><span class="pl-kos">,</span> <span class="pl-s1">propertyKey</span>: <span class="pl-smi">string</span><span class="pl-kos">,</span> <span class="pl-s1">descriptor</span>: <span class="pl-smi">TypedPropertyDescriptor</span><span class="pl-kos">&lt;</span><span class="pl-kos">(</span>...<span class="pl-s1">args</span>: <span class="pl-smi">any</span><span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">T</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">var</span> <span class="pl-s1">originalMethod</span> <span class="pl-c1">=</span> <span class="pl-s1">descriptor</span><span class="pl-kos">.</span><span class="pl-c1">value</span><span class="pl-kos">;</span> <span class="pl-c">// save a reference to the original method</span>

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

        <span class="pl-k">return</span> <span class="pl-s1">newDescriptor</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-en">len</span><span class="pl-kos">(</span><span class="pl-s1">val</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span>: <span class="pl-smi">number</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-s1">val</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-smi">MyClass</span> <span class="pl-kos">{</span>
    @<span class="pl-s1">wrap</span><span class="pl-c1"></span><span class="pl-c1">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">,</span> <span class="pl-smi">number</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">len</span><span class="pl-kos">)</span>
    <span class="pl-en">myMethod</span><span class="pl-kos">(</span><span class="pl-s1">arg</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-s">"Message -- "</span> <span class="pl-c1">+</span> <span class="pl-s1">arg</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-k">const</span> <span class="pl-s1">t</span>: <span class="pl-smi">number</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-smi">MyClass</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">myMethod</span><span class="pl-kos">(</span><span class="pl-s">"testing"</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto"><strong>Expected behavior:</strong><br>
I expect this to compile, and modify the return type of <code class="notranslate">MyClass#myMethod</code>.</p>
<p dir="auto"><strong>Actual behavior:</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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[]) =&gt; number; }' is not assignable to type 'void'.
decorators-broken.ts(31,7): error TS2322: Type 'string' is not assignable to type 'number'."><pre class="notranslate"><code class="notranslate">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[]) =&gt; number; }' is not assignable to type 'void'.
decorators-broken.ts(31,7): error TS2322: Type 'string' is not assignable to type 'number'.
</code></pre></div>
<p dir="auto">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 <code class="notranslate">MethodDecorator</code>'s type signature, this is probably intentional:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type MethodDecorator = &lt;T&gt;(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor&lt;T&gt;): TypedPropertyDescriptor&lt;T&gt; | void;"><pre class="notranslate"><code class="notranslate">type MethodDecorator = &lt;T&gt;(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor&lt;T&gt;): TypedPropertyDescriptor&lt;T&gt; | void;
</code></pre></div>
<p dir="auto">Can we add something like the following?</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type MutatingMethodDecorator = &lt;T, U&gt;(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor&lt;T&gt;): TypedPropertyDescriptor&lt;U&gt; | void;"><pre class="notranslate"><code class="notranslate">type MutatingMethodDecorator = &lt;T, U&gt;(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor&lt;T&gt;): TypedPropertyDescriptor&lt;U&gt; | void;
</code></pre></div>
<p dir="auto">If we can get this to type check properly, we would have perfect support for boilerplate-free mixins:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="declare function Blah&lt;T&gt;(target: T): T &amp; {foo: number}

@Blah
class Foo {
    bar() {
        return this.foo; // Property 'foo' does not exist on type 'Foo'
    }
}

new Foo().foo; // Property 'foo' does not exist on type 'Foo'"><pre class="notranslate"><span class="pl-k">declare</span> <span class="pl-k">function</span> <span class="pl-smi">Blah</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">target</span>: <span class="pl-smi">T</span><span class="pl-kos">)</span>: <span class="pl-smi">T</span> <span class="pl-c1">&amp;</span> <span class="pl-kos">{</span><span class="pl-c1">foo</span>: <span class="pl-smi">number</span><span class="pl-kos">}</span>

@<span class="pl-smi">Blah</span>
<span class="pl-k">class</span> <span class="pl-smi">Foo</span> <span class="pl-kos">{</span>
    <span class="pl-en">bar</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">foo</span><span class="pl-kos">;</span> <span class="pl-c">// Property 'foo' does not exist on type 'Foo'</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-k">new</span> <span class="pl-smi">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">foo</span><span class="pl-kos">;</span> <span class="pl-c">// Property 'foo' does not exist on type 'Foo'</span></pre></div>