<p dir="auto"><strong>TypeScript Version:</strong></p>
<p dir="auto">master</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="interface F {
  (g: () =&gt; void): number; // if this line is removed, tsc gives a correct error.
  (g: (i: (p: number) =&gt; number) =&gt; void): number;
}
var f: F;
f(i =&gt; h(i));
function h(i: (p: string) =&gt; string): string {
  return i('');
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">F</span> <span class="pl-kos">{</span>
  <span class="pl-kos">(</span><span class="pl-s1">g</span>: <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">)</span>: <span class="pl-smi">number</span><span class="pl-kos">;</span> <span class="pl-c">// if this line is removed, tsc gives a correct error.</span>
  <span class="pl-kos">(</span><span class="pl-s1">g</span>: <span class="pl-kos">(</span><span class="pl-s1">i</span>: <span class="pl-kos">(</span><span class="pl-s1">p</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">)</span>: <span class="pl-smi">number</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">var</span> <span class="pl-s1">f</span>: <span class="pl-smi">F</span><span class="pl-kos">;</span>
<span class="pl-en">f</span><span class="pl-kos">(</span><span class="pl-s1">i</span> <span class="pl-c1">=&gt;</span> <span class="pl-en">h</span><span class="pl-kos">(</span><span class="pl-s1">i</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">h</span><span class="pl-kos">(</span><span class="pl-s1">i</span>: <span class="pl-kos">(</span><span class="pl-s1">p</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">string</span><span class="pl-kos">)</span>: <span class="pl-smi">string</span> <span class="pl-kos">{</span>
  <span class="pl-k">return</span> <span class="pl-en">i</span><span class="pl-kos">(</span><span class="pl-s">''</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto"><strong>Expected behavior:</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="index.ts(6,10): error TS2345: Argument of type '(p: number) =&gt; number' is not as signable to parameter of type '(p: string) =&gt; string'.
  Types of parameters 'p' and 'p' are incompatible.
    Type 'string' is not assignable to type 'number'."><pre class="notranslate"><code class="notranslate">index.ts(6,10): error TS2345: Argument of type '(p: number) =&gt; number' is not as signable to parameter of type '(p: string) =&gt; string'.
  Types of parameters 'p' and 'p' are incompatible.
    Type 'string' is not assignable to type 'number'.
</code></pre></div>
<p dir="auto"><strong>Actual behavior:</strong></p>
<p dir="auto">pass</p>
<h1 dir="auto">Motivation</h1>
<p dir="auto">Libraries such as Knockout use overloaded functions, for example:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var x = new MyKnockoutModel();
console.log(x.customerName()); // string
x.customerName('bob'); // OK
x.customerName(42); // Error, 42 is not a string"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-smi">MyKnockoutModel</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-s1">x</span><span class="pl-kos">.</span><span class="pl-en">customerName</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">// string</span>
<span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-en">customerName</span><span class="pl-kos">(</span><span class="pl-s">'bob'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// OK</span>
<span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-en">customerName</span><span class="pl-kos">(</span><span class="pl-c1">42</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// Error, 42 is not a string</span></pre></div>
<p dir="auto">We can model these in TypeScript:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface KnockoutElement&lt;T&gt; {
  // Getter
  (): T;
  // Setter
  (value: T): void;
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">KnockoutElement</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-c">// Getter</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-c">// Setter</span>
  <span class="pl-kos">(</span><span class="pl-s1">value</span>: <span class="pl-smi">T</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></pre></div>
<p dir="auto">However, these overloads turn out to not be safe when used in callbacks. For example:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function readFile(finished: (contents: string) =&gt; void) { /*... */ }
var ko: KnockoutElement&lt;number&gt;;
readFile(ko); // No error, but passes a string to a number-expecting setter!"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">readFile</span><span class="pl-kos">(</span><span class="pl-s1">finished</span>: <span class="pl-kos">(</span><span class="pl-s1">contents</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</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-c">/*... */</span> <span class="pl-kos">}</span>
<span class="pl-k">var</span> <span class="pl-s1">ko</span>: <span class="pl-smi">KnockoutElement</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
<span class="pl-en">readFile</span><span class="pl-kos">(</span><span class="pl-s1">ko</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// No error, but passes a string to a number-expecting setter!</span></pre></div>
<p dir="auto">This is because we look at all the candidate source signatures, reject the <code class="notranslate">(x :number) =&gt; void</code> signature for having an incompatible type, and accept the <code class="notranslate">() =&gt; T</code> signature because it has fewer parameters (an acceptable variance).</p>
<p dir="auto">This behavior does not map to any actual runtime behavior. The invoker's side might check the <code class="notranslate">.length</code> property of the function to determine what kind of arguments to pass, and the invokee's side might check <code class="notranslate">arguments.length</code> to determine which overload was intended, but the invoker cannot tell what the expected parameter <em>type</em> of the function is, and the invokee reasonably expects to be called with the correct <em>type</em> given a certain <em>arity</em>.</p>
<h1 dir="auto">Proposal</h1>
<p dir="auto">As an example, if a callback declaration says it’s going to invoke <code class="notranslate">f</code> with two parameters, we should not consider overloads of <code class="notranslate">f</code> which take zero arguments if an overload with one or two arguments exists.</p>
<p dir="auto">In 3.8.3 / 3.8.4:</p>
<blockquote>
<p dir="auto">M is a non-specialized call or construct signature and S’ contains a call or construct signature N where […]</p>
</blockquote>
<p dir="auto">Change to</p>
<blockquote>
<p dir="auto">M is a non-specialized call or construct signature and S’ contains a call or construct signature N where no other call or construct signature in S’ has more parameters than N but not more than M, and […]</p>
</blockquote>
<h1 dir="auto">Analysis</h1>
<p dir="auto">A sample implementation of this rule breaks no existing tests. Check <code class="notranslate">stopParameterNeglect</code> branch for code/tests.</p>