<p dir="auto">At the moment compiler insists on having valid identifier on right side of <code class="notranslate">typeof</code> so following code is not valid:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var x : typeof (1+ 2);
var y : typeof this;"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">x</span> : <span class="pl-k">typeof</span><span class="pl-k"></span> <span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-c1">+</span> <span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">y</span> : <span class="pl-k">typeof</span> <span class="pl-s1">this</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">even though it's possible to assign the expression to variable and then capture the type form that:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var x_ = 1+2;
var x = typeof x;
var y_ = this;
var y = typeof y_;"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">x_</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-c1">+</span><span class="pl-c1">2</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">x</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">y_</span> <span class="pl-c1">=</span> <span class="pl-smi">this</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">y_</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">I propose to allow capturing type of any valid expression. The expression itself wouldn't be evaluated.</p>
<h2 dir="auto">Working Implementation for this Proposal</h2>
<p dir="auto">Try it out: <code class="notranslate">npm install yortus-typescript-typeof</code></p>
<p dir="auto">View the diff: <a href="https://github.com/yortus/TypeScript/compare/master...yortus:type-query-powerup">here</a>.</p>
<h2 dir="auto">Problem Scenario</h2>
<p dir="auto">TypeScript's type inference covers most cases very well. However there remain some situations where there is no obvious way to reference an anonymous type, even though the compiler is able to infer it. Some examples:</p>
<h5 dir="auto">I have a strongly-typed collection but the element type is anonymous/unknown, how can I reference the element type? (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="93230828" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/3749" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/3749/hovercard" href="https://github.com/microsoft/TypeScript/issues/3749">#3749</a>)</h5>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Mapping to a complex anonymous type. How to reference the element type?
var data = [1, 2, 3].map(v =&gt; ({ raw: v, square: v * v }));
function checkItem(item: typeof data[0] /* ERROR */) {...}

// A statically-typed dictionary. How to reference a property type?
var things = { 'thing-1': 'baz', 'thing-2': 42, ... };
type Thing2Type = typeof things['thing-2']; // ERROR

// A strongly-typed collection with special indexer syntax. How to reference the element type?
var nodes = document.getElementsByTagName('li');
type ItemType = typeof nodes.item(0); // ERROR"><pre class="notranslate"><span class="pl-c">// Mapping to a complex anonymous type. How to reference the element type?</span>
<span class="pl-k">var</span> <span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-en">map</span><span class="pl-kos">(</span><span class="pl-s1">v</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">(</span><span class="pl-kos">{</span> <span class="pl-c1">raw</span>: <span class="pl-s1">v</span><span class="pl-kos">,</span> <span class="pl-c1">square</span>: <span class="pl-s1">v</span> <span class="pl-c1">*</span> <span class="pl-s1">v</span> <span class="pl-kos">}</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">checkItem</span><span class="pl-kos">(</span><span class="pl-s1">item</span>: <span class="pl-k">typeof</span> <span class="pl-s1">data</span><span class="pl-kos">[</span><span class="pl-c1">0</span><span class="pl-kos">]</span> <span class="pl-c">/* ERROR */</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>...<span class="pl-kos">}</span>

<span class="pl-c">// A statically-typed dictionary. How to reference a property type?</span>
<span class="pl-k">var</span> <span class="pl-s1">things</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-s">'thing-1'</span>: <span class="pl-s">'baz'</span><span class="pl-kos">,</span> <span class="pl-s">'thing-2'</span>: <span class="pl-c1">42</span><span class="pl-kos">,</span> ... <span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-k">type</span> <span class="pl-smi">Thing2Type</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">things</span><span class="pl-kos">[</span><span class="pl-s">'thing-2'</span><span class="pl-kos">]</span><span class="pl-kos">;</span> <span class="pl-c">// ERROR</span>

<span class="pl-c">// A strongly-typed collection with special indexer syntax. How to reference the element type?</span>
<span class="pl-k">var</span> <span class="pl-s1">nodes</span> <span class="pl-c1">=</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementsByTagName</span><span class="pl-kos">(</span><span class="pl-s">'li'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">type</span> <span class="pl-smi">ItemType</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">nodes</span><span class="pl-kos">.</span><span class="pl-en">item</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ERROR</span></pre></div>
<h5 dir="auto">A function returns a local/anonymous/inaccessible type, how can I reference this return type? (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="99760852" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4233" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4233/hovercard" href="https://github.com/microsoft/TypeScript/issues/4233">#4233</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="123190033" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/6179" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/6179/hovercard" href="https://github.com/microsoft/TypeScript/issues/6179">#6179</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="123809442" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/6239" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/6239/hovercard" href="https://github.com/microsoft/TypeScript/issues/6239">#6239</a>)</h5>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// A factory function that returns an instance of a local class
function myAPIFactory($http: HttpSvc, id: number) {
    class MyAPI {
        constructor(http) {...}
        foo() {...}
        bar() {...}
        static id = id;
    }
    return new MyAPI($http);
}
function augmentAPI(api: MyAPI /* ERROR */) {...}"><pre class="notranslate"><span class="pl-c">// A factory function that returns an instance of a local class</span>
<span class="pl-k">function</span> <span class="pl-en">myAPIFactory</span><span class="pl-kos">(</span><span class="pl-s1">$http</span>: <span class="pl-smi">HttpSvc</span><span class="pl-kos">,</span> <span class="pl-s1">id</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">class</span> <span class="pl-smi">MyAPI</span> <span class="pl-kos">{</span>
        <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">http</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>...<span class="pl-kos">}</span>
        <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</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-kos">}</span>
        <span class="pl-k">static</span> <span class="pl-c1">id</span> <span class="pl-c1">=</span> <span class="pl-s1">id</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">MyAPI</span><span class="pl-kos">(</span><span class="pl-s1">$http</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">augmentAPI</span><span class="pl-kos">(</span><span class="pl-s1">api</span>: <span class="pl-smi">MyAPI</span> <span class="pl-c">/* ERROR */</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>...<span class="pl-kos">}</span></pre></div>
<h5 dir="auto">I have an interface with a complex anonymous shape, how can I refer to the types of its properties and sub-properties? (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="104030035" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4555" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4555/hovercard" href="https://github.com/microsoft/TypeScript/issues/4555">#4555</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="104898491" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4640" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4640/hovercard" href="https://github.com/microsoft/TypeScript/issues/4640">#4640</a>)</h5>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Declare an interface DRY-ly and without introducing extra type names
interface MyInterface {
    prop1: {
        big: {
            complex: {
                anonymous: { type: {} }
            }
        }
    },

    // prop2 shares some structure with prop1
    prop2: typeof MyInterface.prop1.big.complex; // ERROR
}"><pre class="notranslate"><span class="pl-c">// Declare an interface DRY-ly and without introducing extra type names</span>
<span class="pl-k">interface</span> <span class="pl-smi">MyInterface</span> <span class="pl-kos">{</span>
    <span class="pl-c1">prop1</span>: <span class="pl-kos">{</span>
        <span class="pl-c1">big</span>: <span class="pl-kos">{</span>
            <span class="pl-c1">complex</span>: <span class="pl-kos">{</span>
                <span class="pl-c1">anonymous</span>: <span class="pl-kos">{</span> <span class="pl-c1">type</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-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c">// prop2 shares some structure with prop1</span>
    <span class="pl-c1">prop2</span>: <span class="pl-k">typeof</span> <span class="pl-smi">MyInterface</span><span class="pl-kos">.</span><span class="pl-c1">prop1</span><span class="pl-kos">.</span><span class="pl-c1">big</span><span class="pl-kos">.</span><span class="pl-c1">complex</span><span class="pl-kos">;</span> <span class="pl-c">// ERROR</span>
<span class="pl-kos">}</span></pre></div>
<h2 dir="auto">Why do we need to Reference Anonymous/Inferred Types?</h2>
<p dir="auto">One example is declaring a function that takes an anonymous type as a parameter. We need to reference the type somehow in the parameter's type annotation, otherwise the parameter will have to be typed as <code class="notranslate">any</code>.</p>
<h2 dir="auto">Current Workarounds</h2>
<p dir="auto">Declare a dummy variable with an initializer that infers the desired type <strong>without</strong> evaluating the expression (this is important because we don't want runtime side-effects, just type inference). For example:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let dummyReturnVal = null &amp;&amp; someFunction(0, ''); // NB: someFunction is never called!
let ReturnType = typeof dummyReturnVal;           // Now we have a reference to the return type"><pre class="notranslate"><span class="pl-k">let</span> <span class="pl-s1">dummyReturnVal</span> <span class="pl-c1">=</span> <span class="pl-c1">null</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-en">someFunction</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">,</span> <span class="pl-s">''</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// NB: someFunction is never called!</span>
<span class="pl-k">let</span> <span class="pl-smi">ReturnType</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">dummyReturnVal</span><span class="pl-kos">;</span>           <span class="pl-c">// Now we have a reference to the return type</span></pre></div>
<p dir="auto">This workaround has a few drawbacks:</p>
<ul dir="auto">
<li>very clearly a kludge, unclear for readers</li>
<li>identifier pollution (must introduce a variable like <code class="notranslate">dummyReturnValue</code>)</li>
<li>does't work in ambient contexts, because it requires an imperative statement</li>
</ul>
<h2 dir="auto">Proposed Solution</h2>
<p dir="auto"><em>(NB: This solution was already suggested in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="99760852" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4233" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4233/hovercard" href="https://github.com/microsoft/TypeScript/issues/4233">#4233</a>, but that issue is tagged 'Needs Proposal', and there are several other closely related issues, hence this separate issue.)</em></p>
<p dir="auto">Allow <code class="notranslate">typeof</code>'s operand to be an arbitrary expression. This is already allowed for <code class="notranslate">typeof expr</code> in a value position like <code class="notranslate">if (typeof foo() === 'string')</code>. But this proposal also allows an arbitrary expression when <code class="notranslate">typeof</code> is used in a type position as a type query, eg <code class="notranslate">type ElemType = typeof list[0]</code>.</p>
<p dir="auto">This proposal already aligns closely with the current wording of the spec:</p>
<blockquote>
<p dir="auto">Type queries are useful for capturing anonymous types that are generated by various constructs such as object literals, function declarations, and namespace declarations.</p>
</blockquote>
<p dir="auto">So this proposal is just extending that usefulness to the currently unserved situations like in the examples above.</p>
<h2 dir="auto">Syntax and Semantics</h2>
<p dir="auto">The semantics are exactly as already stated in the <a href="https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#4.18.6">spec 4.18.6</a>:</p>
<blockquote>
<p dir="auto">The 'typeof' operator takes an operand of any type and produces a value of the String primitive type. In positions where a type is expected, 'typeof' can also be used in a type query (section 3.8.10) to produce the type of an expression.</p>
</blockquote>
<p dir="auto">The proposed difference relates to <a href="https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.8.10">section 3.8.10</a> quoted below, where the struck-through text would be removed and the bold text added:</p>
<blockquote>
<p dir="auto">A type query consists of the keyword typeof followed by <strike>an expression. The expression is restricted to a single identifier or a sequence of identifiers separated by periods. The expression is processed as an identifier expression (section 4.3) or property access expression (section 4.13)</strike> <strong>a unary expression</strong>, the widened type (section 3.12) of which becomes the result. Similar to other static typing constructs, type queries are erased from the generated JavaScript code and add no run-time overhead.</p>
</blockquote>
<p dir="auto">A point that must be emphasized (which I thought was also in the spec but can't find it) is that type queries <strong>do not</strong> evaluate their operand. That's true currently and would remain true for more complex expressions.</p>
<p dir="auto">This proposal doesn't introduce any novel syntax, it just makes <code class="notranslate">typeof</code> less restrictive in the types of expressions it can query.</p>
<h2 dir="auto">Examples</h2>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Mapping to a complex anonymous type. How to reference the element type?
var data = [1, 2, 3].map(v =&gt; ({ raw: v, square: v * v }));
function checkItem(item: typeof data[0]) {...} // OK: item type is {raw:number, square:number}

// A statically-typed dictionary. How to reference a property type?
var things = { 'thing-1': 'baz', 'thing-2': 42, ... };
type Thing2Type = typeof things['thing-2']; // OK: Thing2Type is number

// A strongly-typed collection with special indexer syntax. How to reference the element type?
var nodes = document.getElementsByTagName('li');
type ItemType = typeof nodes.item(0); // OK: ItemType is HTMLLIElement

// A factory function that returns an instance of a local class
function myAPIFactory($http: HttpSvc, id: number) {
    class MyAPI {
        constructor(http) {...}
        foo() {...}
        bar() {...}
        static id = id;
    }
    return new MyAPI($http);
}
type MyAPI = typeof myAPIFactory(null, 0); // OK: MyAPI is myAPIFactory's return type
function augmentAPI(api: MyAPI) {...} // OK

// Declare an interface DRY-ly and without introducing extra type names
interface MyInterface {
    prop1: {
        big: {
            complex: {
                anonymous: { type: {} }
            }
        }
    },

    // prop2 shares some structure with prop1
    prop2: typeof (&lt;MyInterface&gt;null).prop1.big.complex; // OK: prop2 type is {anonymous: {type: {}}}
}"><pre class="notranslate"><span class="pl-c">// Mapping to a complex anonymous type. How to reference the element type?</span>
<span class="pl-k">var</span> <span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-en">map</span><span class="pl-kos">(</span><span class="pl-s1">v</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">(</span><span class="pl-kos">{</span> <span class="pl-c1">raw</span>: <span class="pl-s1">v</span><span class="pl-kos">,</span> <span class="pl-c1">square</span>: <span class="pl-s1">v</span> <span class="pl-c1">*</span> <span class="pl-s1">v</span> <span class="pl-kos">}</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">checkItem</span><span class="pl-kos">(</span><span class="pl-s1">item</span>: <span class="pl-k">typeof</span> <span class="pl-s1">data</span><span class="pl-kos">[</span><span class="pl-c1">0</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">// OK: item type is {raw:number, square:number}</span>

<span class="pl-c">// A statically-typed dictionary. How to reference a property type?</span>
<span class="pl-k">var</span> <span class="pl-s1">things</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-s">'thing-1'</span>: <span class="pl-s">'baz'</span><span class="pl-kos">,</span> <span class="pl-s">'thing-2'</span>: <span class="pl-c1">42</span><span class="pl-kos">,</span> ... <span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-k">type</span> <span class="pl-smi">Thing2Type</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">things</span><span class="pl-kos">[</span><span class="pl-s">'thing-2'</span><span class="pl-kos">]</span><span class="pl-kos">;</span> <span class="pl-c">// OK: Thing2Type is number</span>

<span class="pl-c">// A strongly-typed collection with special indexer syntax. How to reference the element type?</span>
<span class="pl-k">var</span> <span class="pl-s1">nodes</span> <span class="pl-c1">=</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementsByTagName</span><span class="pl-kos">(</span><span class="pl-s">'li'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">type</span> <span class="pl-smi">ItemType</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-s1">nodes</span><span class="pl-kos">.</span><span class="pl-en">item</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// OK: ItemType is HTMLLIElement</span>

<span class="pl-c">// A factory function that returns an instance of a local class</span>
<span class="pl-k">function</span> <span class="pl-en">myAPIFactory</span><span class="pl-kos">(</span><span class="pl-s1">$http</span>: <span class="pl-smi">HttpSvc</span><span class="pl-kos">,</span> <span class="pl-s1">id</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">class</span> <span class="pl-smi">MyAPI</span> <span class="pl-kos">{</span>
        <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">http</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>...<span class="pl-kos">}</span>
        <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</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-kos">}</span>
        <span class="pl-k">static</span> <span class="pl-c1">id</span> <span class="pl-c1">=</span> <span class="pl-s1">id</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">MyAPI</span><span class="pl-kos">(</span><span class="pl-s1">$http</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">type</span> <span class="pl-smi">MyAPI</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-en">myAPIFactory</span><span class="pl-kos">(</span><span class="pl-c1">null</span><span class="pl-kos">,</span> <span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// OK: MyAPI is myAPIFactory's return type</span>
<span class="pl-k">function</span> <span class="pl-en">augmentAPI</span><span class="pl-kos">(</span><span class="pl-s1">api</span>: <span class="pl-smi">MyAPI</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>...<span class="pl-kos">}</span> <span class="pl-c">// OK</span>

<span class="pl-c">// Declare an interface DRY-ly and without introducing extra type names</span>
<span class="pl-k">interface</span> <span class="pl-smi">MyInterface</span> <span class="pl-kos">{</span>
    <span class="pl-c1">prop1</span>: <span class="pl-kos">{</span>
        <span class="pl-c1">big</span>: <span class="pl-kos">{</span>
            <span class="pl-c1">complex</span>: <span class="pl-kos">{</span>
                <span class="pl-c1">anonymous</span>: <span class="pl-kos">{</span> <span class="pl-c1">type</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-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c">// prop2 shares some structure with prop1</span>
    <span class="pl-c1">prop2</span>: <span class="pl-k">typeof</span><span class="pl-k"></span> <span class="pl-kos">(</span><span class="pl-kos">&lt;</span><span class="pl-smi">MyInterface</span><span class="pl-kos">&gt;</span><span class="pl-c1">null</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">prop1</span><span class="pl-kos">.</span><span class="pl-c1">big</span><span class="pl-kos">.</span><span class="pl-c1">complex</span><span class="pl-kos">;</span> <span class="pl-c">// OK: prop2 type is {anonymous: {type: {}}}</span>
<span class="pl-kos">}</span></pre></div>
<h2 dir="auto">Discussion of Pros/Cons</h2>
<p dir="auto"><strong>Against</strong>: Poor syntax aesthetics. Alternative syntaxes addressing individual cases have been suggested in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="123190033" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/6179" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/6179/hovercard" href="https://github.com/microsoft/TypeScript/issues/6179">#6179</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="123809442" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/6239" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/6239/hovercard" href="https://github.com/microsoft/TypeScript/issues/6239">#6239</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="104030035" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4555" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4555/hovercard" href="https://github.com/microsoft/TypeScript/issues/4555">#4555</a> and <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="104898491" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4640" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4640/hovercard" href="https://github.com/microsoft/TypeScript/issues/4640">#4640</a>.</p>
<p dir="auto"><strong>For</strong>: Other syntaxes may look better for their specific cases, but they are all different from each other and each only solve one specific problem. This proposal solves the problems raised in all those issues, and the developer doesn't need to learn any new syntax(es).</p>
<p dir="auto"><strong>Against</strong>: An expression in a type position is confusing.</p>
<p dir="auto"><strong>For</strong>: TypeScript already overloads <code class="notranslate">typeof</code> with two meanings, as a type query it already accepts an expression in a type position and gets its type without evaluating it. This just relaxes the constraints on what that expression can be so that it can solve the problems raised in this issue.</p>
<p dir="auto"><strong>Against</strong>: This could be abused to write huge long multi-line type queries.</p>
<p dir="auto"><strong>For</strong>: There's no good reason to do that in a type query, but there are good reasons to allow more complex expressions. This is basically Martin Fowler's <a href="http://martinfowler.com/bliki/SoftwareDevelopmentAttitude.html" rel="nofollow">enabling vs directing</a>.</p>
<h2 dir="auto">Design Impact, Questions, and Further Work</h2>
<h5 dir="auto">Compatibility</h5>
<p dir="auto">This is a purely backward-compatible change. All existing code is unaffected. Using the additional capabilities of <code class="notranslate">typeof</code> is opt-in.</p>
<h5 dir="auto">Performance</h5>
<p dir="auto">Looking at the diff you can see the changes are very minor. The compiler already knows the types being queried, this just surfaces them to the developer. I would expect negligable performance impact, but I don't know how to test this.</p>
<h5 dir="auto">Tooling</h5>
<p dir="auto">I have set up VS Code to use a version of TypeScript with this proposal implemented as its language service, and all the syntax highlighting and intellisense is flawless as far as I have tested it.</p>
<h5 dir="auto">Complex expressions may occur in <code class="notranslate">.d.ts</code> files</h5>
<p dir="auto"><code class="notranslate">typeof</code>'s operand could be any expression, including an IIFE, or a class expression complete with method bodies, etc. I can't think of any reason to do that, it's just no longer an error, even inside  a<code class="notranslate">.d.ts</code> file (<code class="notranslate">typeof</code> can be used - and is useful - in ambient contexts). So a consequence of this proposal is that "statements cannot appear in ambient contexts" is no longer strictly true.</p>
<h5 dir="auto">Recursive types are handled robustly</h5>
<p dir="auto">The compiler seems to already have all the logic in place needed to deal with things like this:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function foo&lt;X,Y&gt;(x: X, y: Y) {
    var result: typeof foo(x, y); // ERROR: 'result' is referenced in its own type annotation
    return result;
}"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">foo</span><span class="pl-c1">&lt;</span><span class="pl-smi">X</span><span class="pl-kos">,</span><span class="pl-smi">Y</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">x</span>: <span class="pl-smi">X</span><span class="pl-kos">,</span> <span class="pl-s1">y</span>: <span class="pl-smi">Y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">var</span> <span class="pl-s1">result</span>: <span class="pl-k">typeof</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ERROR: 'result' is referenced in its own type annotation</span>
    <span class="pl-k">return</span> <span class="pl-s1">result</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<h5 dir="auto">Can query the return type of an overloaded function</h5>
<p dir="auto">It is not ambiguous; it picks the overload that matches the query's expression:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="declare function foo(a: boolean): string;
declare function foo(a: number): any[];
type P = typeof foo(0);    // P is any[]
type Q = typeof foo(true); // Q is string"><pre class="notranslate"><span class="pl-k">declare</span> <span class="pl-k">function</span> <span class="pl-s1">foo</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">boolean</span><span class="pl-kos">)</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
<span class="pl-k">declare</span> <span class="pl-k">function</span> <span class="pl-s1">foo</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">number</span><span class="pl-kos">)</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-k">type</span> <span class="pl-smi">P</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span>    <span class="pl-c">// P is any[]</span>
<span class="pl-k">type</span> <span class="pl-smi">Q</span> <span class="pl-c1">=</span> <span class="pl-k">typeof</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// Q is string</span></pre></div>