<p dir="auto">This is strongly related to <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="107375551" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4881" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4881/hovercard" href="https://github.com/microsoft/TypeScript/issues/4881">#4881</a> but I'm not sure if it's feature request or if it's really a bug. Given that the Decorators spec states the decorator can return a new constructor function, it sort of seems like it should work.</p>
<p dir="auto">The following example uses constructor function types and very nearly works.</p>
<p dir="auto"><a href="http://www.typescriptlang.org/Playground#src=interface%20ConstructorFunction%3CT%3E%20%7B%0D%0A%20%20%20%20new%20%28...args%3Aany%5B%5D%29%3AT%3B%0D%0A%20%20%20%20prototype%3AT%0D%0A%7D%0D%0A%0D%0Ainterface%20Disappearing%20%7B%0D%0A%20%20%20%20isVisible%28%29%3Aboolean%3B%0D%0A%20%20%20%20vanish%28%29%3Avoid%3B%0D%0A%7D%0D%0A%0D%0Afunction%20Disappearing%3CT%3E%28ctor%3AConstructorFunction%3CT%3E%29%3AConstructorFunction%3CT%20%26%20Disappearing%3E%20%7B%0D%0A%20%20%20%20let%20result%20%3D%20%3CConstructorFunction%3CT%20%26%20Disappearing%3E%3Ector%3B%0D%0A%20%20%20%20result.prototype.isVisible%20%3D%20%28%29%20%3D%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20!this%5B'_hasDisappeared'%5D%3B%0D%0A%20%20%20%20%7D%3B%0D%0A%20%20%20%20result.prototype.vanish%20%3D%20%28%29%20%3D%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20this%5B'_hasDisappeared'%5D%20%3D%20true%3B%0D%0A%20%20%20%20%7D%3B%0D%0A%20%20%20%20return%20result%3B%0D%0A%7D%0D%0A%0D%0A%2F%2F%20This%20seems%20like%20it%20should%20work%0D%0A%2F%2F%20%40Disappearing%0D%0A%2F%2F%20class%20Cat%20%7B%0D%0A%2F%2F%20%20%20%20%20constructor%28private%20name%3Astring%29%20%7B%7D%0D%0A%2F%2F%20%7D%0D%0A%0D%0A%2F%2F%20but%20I%20have%20to%20do%20this%0D%0A%40Disappearing%0D%0Aclass%20Cat%20implements%20Disappearing%20%7B%0D%0A%20%20%20%20constructor%28private%20name%3Astring%29%20%7B%7D%0D%0A%20%20%20%20isVisible%28%29%20%7Breturn%20false%7D%0D%0A%20%20%20%20vanish%28%29%7B%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F%20let%20ctor%20%3D%20wrappedBlah%28Cat%29%3B%0D%0Alet%20buster%20%3D%20new%20Cat%28'Buster'%29%3B%0D%0Aalert%28%60Is%20Buster%20visible%3F%20-%3E%20%24%7Bbuster.isVisible%28%29%7D%60%29%3B%0D%0Abuster.vanish%28%29%3B%0D%0Aalert%28%60Is%20Buster%20visible%3F%20-%3E%20%24%7Bbuster.isVisible%28%29%7D%60%29%3B%0D%0A%0D%0A" rel="nofollow">View this in playground</a></p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface ConstructorFunction&lt;T&gt; {
    new (...args:any[]):T;
    prototype:T
}

interface Disappearing {
    isVisible():boolean;
    vanish():void;
}

function Disappearing&lt;T&gt;(ctor:ConstructorFunction&lt;T&gt;):ConstructorFunction&lt;T &amp; Disappearing&gt; {
    let result = &lt;ConstructorFunction&lt;T &amp; Disappearing&gt;&gt;ctor;
    result.prototype.isVisible = () =&gt; {
        return !this['_hasDisappeared'];
    };
    result.prototype.vanish = () =&gt; {
        this['_hasDisappeared'] = true;
    };
    return result;
}

// This seems like it should work
// @Disappearing
// class Cat {
//     constructor(private name:string) {}
// }

// but I have to do this
@Disappearing
class Cat implements Disappearing {
    constructor(private name:string) {}
    isVisible() {return false}
    vanish(){}
}

// let ctor = wrappedBlah(Cat);
let buster = new Cat('Buster');
alert(`Is Buster visible? -&gt; ${buster.isVisible()}`);
buster.vanish();
alert(`Is Buster visible? -&gt; ${buster.isVisible()}`);"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">ConstructorFunction</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-k">new</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-smi">T</span><span class="pl-kos">;</span>
    <span class="pl-c1">prototype</span>:<span class="pl-smi">T</span>
<span class="pl-kos">}</span>

<span class="pl-k">interface</span> <span class="pl-smi">Disappearing</span> <span class="pl-kos">{</span>
    <span class="pl-c1">isVisible</span><span class="pl-kos">(</span><span class="pl-kos">)</span>:<span class="pl-smi">boolean</span><span class="pl-kos">;</span>
    <span class="pl-c1">vanish</span><span class="pl-kos">(</span><span class="pl-kos">)</span>:<span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-smi">Disappearing</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">ctor</span>:<span class="pl-smi">ConstructorFunction</span><span class="pl-kos">&lt;</span><span class="pl-smi">T</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span>:<span class="pl-smi">ConstructorFunction</span><span class="pl-kos">&lt;</span><span class="pl-smi">T</span> <span class="pl-c1">&amp;</span> <span class="pl-smi">Disappearing</span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-k">let</span> <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">ConstructorFunction</span><span class="pl-kos">&lt;</span><span class="pl-smi">T</span> <span class="pl-c1">&amp;</span> <span class="pl-smi">Disappearing</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-s1">ctor</span><span class="pl-kos">;</span>
    <span class="pl-s1">result</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">isVisible</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-c1">!</span><span class="pl-smi">this</span><span class="pl-kos">[</span><span class="pl-s">'_hasDisappeared'</span><span class="pl-kos">]</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span><span class="pl-kos">;</span>
    <span class="pl-s1">result</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">vanish</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-smi">this</span><span class="pl-kos">[</span><span class="pl-s">'_hasDisappeared'</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-c1">true</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">result</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-c">// This seems like it should work</span>
<span class="pl-c">// <span class="pl-k">@Disappearing</span></span>
<span class="pl-c">// class Cat {</span>
<span class="pl-c">//     constructor(private name:string) {}</span>
<span class="pl-c">// }</span>

<span class="pl-c">// but I have to do this</span>
@<span class="pl-smi">Disappearing</span>
<span class="pl-k">class</span> <span class="pl-smi">Cat</span> <span class="pl-k">implements</span> <span class="pl-smi">Disappearing</span> <span class="pl-kos">{</span>
    <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-k">private</span> <span class="pl-s1">name</span>:<span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
    <span class="pl-en">isVisible</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-c1">false</span><span class="pl-kos">}</span>
    <span class="pl-en">vanish</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span><span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-c">// let ctor = wrappedBlah(Cat);</span>
<span class="pl-k">let</span> <span class="pl-s1">buster</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-smi">Cat</span><span class="pl-kos">(</span><span class="pl-s">'Buster'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-en">alert</span><span class="pl-kos">(</span><span class="pl-s">`Is Buster visible? -&gt; <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">buster</span><span class="pl-kos">.</span><span class="pl-en">isVisible</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">}</span></span>`</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-s1">buster</span><span class="pl-kos">.</span><span class="pl-en">vanish</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-en">alert</span><span class="pl-kos">(</span><span class="pl-s">`Is Buster visible? -&gt; <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">buster</span><span class="pl-kos">.</span><span class="pl-en">isVisible</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">}</span></span>`</span><span class="pl-kos">)</span><span class="pl-kos">;</span></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>