microsoft / microsoft/TypeScript
Method overloads fail to resolve correctly when using mapped types with conditional generics and optional parameters
まだ誰も着手していません。
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.3k
- 平均マージ
- 2日 4時間
- マージ済み PR(30日)
- 132
説明
### 🔎 Search Terms
method overload, generic mapped types, conditional generics, overload resolution, optional parameters, Parameters utility type, ReturnType, ConfigurableAPI, overload lost mapped type, call method generic, generic constraint overload
### 🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about overloads and generics
- I was unable to test this on prior versions because the behavior has been consistent since at least 4.9.5
### ⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.9.2#code/PTAEFkEsDtIWwIYBtQCcCmAHVB7AJgK4DGALpDtKAM4AWOA7jAOagk3qgBGBTAsAFBEkCKlVABBAAoBJADwAVUOgAeJdNDxiASuiI5UeWVRKpmAGlAAKAHS2EqJlQBcoBNACeAbQC6ASlAAvAB8rh5BIQDeAqCgetDGqMQk+pbYkABuCGqgcOhs+M6g8v4RAL7RoBUgEHl0eKA46eioSDgImqAAZvpceWqooAAiABoVRMhIsgDSSqrqHQDW6O44nUVBlrn5eC5Tvi46JASo0PLumOgKnlPeQQDcYxPTs2oaYksra-IbW3W7FrZrPZHC5JPYEFtmlQrjcgvtQIdjqdzpd5Ndbg9+DFxkhJjMVK9FstVutNrV8P9QIDgYU3F4-Ac8kizhcYbdQFEsTE0EyTqwaJAqNZfgVPCK8N4bHYHFRfJiYuV+IqBNV5OhjKBGGxQJlTDgCGJxdRIExoFljuqBHENQhMJBAqBoOh6BIZJZOTFqgA5HCgTDgyGoKgVJh5ADKJmYLks-mCoAAROxcTh42YKlUwDoAI4ESAYer+1AQvLNEN5L0EOCcZrRuAEJBkTBISA1x2V6uoWMhAAsACZQAAqHL1xvN5pprkZ0AAeUwZAoyD9AZLqAq2BwRHVVEGWQQ0bwu5cCXMDTn5HiAH4XBFQARMBdUOMqOgr1wcDgkOg3KBSl3KlyYhwM8KCoC9rDvB8nw4C9QAPEgEGsZIAFV72aABhER0BjUAXDghAJ25f9PTAcAR0gJsOELYt+jELUaFPeczSQMYcDgCjlHAckdisPc2yrccuCPSNoCYCwiFfTh30-Nw-wqbFQBggADAASCJOFKABaVSEFKRScNAFSIh0rS1N0gRf0xFUwEAGXJQAAISQgBxFxpyaFo2nqDAqA-AhGK6BBICQYN+Cs0AMOfUAAEYXB9Jci0DMQNOoOh63qRASCIejOjzDVGmaVp2itECSGoEwHVtSBrBxJBLAAclDEgI1METarlf9qgAUVQXBUBcDrlAuUh0HqftgUrdQSCoCxuBKpgcBKyLrAEULwo4XsXOApi4uo5pQCSzoAqCor4hKvDIvKu0qomOr103UQd3g2qLFqtRjFau52rALqepccQHHG6ASpJEgUVAWrjxa0BBUdebXFEE0zU4T9WF9KjAwaNYQYuMGnTc2qlpC-hqlW0AAGYXFIhtyORtGV1oyBtSAxjkGOjUvJHc6AlcS7qrqvQ2M-DiuKeqLntekh3tC779F+-7ckBjHWFB2roHbZpaqhsRoFhkQqARhAkY4ZJtvR4Hldx9XrCAA
### 💻 Code
```ts
// Minimal reproduction showing the bug
class API any>> {
constructor(private methods: T) {}
// Method overloads for better DX
call(method: K): ReturnType;
call(method: K, ...args: Parameters): ReturnType;
call(method: K, ...args: any[]): ReturnType {
return this.methods[method](...args);
}
}
// Test with various method signatures
const api = new API({
// No parameters
getString: () => "hello",
// Required parameter
getNumber: (multiplier: number) => 42 * multiplier,
// Optional parameter
processData: (data: string, options?: { uppercase?: boolean }) =>
options?.uppercase ? data.toUpperCase() : data,
// Multiple parameters with optional
complexMethod: (a: number, b: string, c?: boolean) =>
c ? `${b}-${a}` : `${a}-${b}`
});
// ❌ BUG: Overload resolution fails
// Case 1: No parameters - should match first overload
const str = api.call('getString');
// Error: Expected 2 arguments, but got 1.
// Case 2: Optional parameter - fails
const data1 = api.call('processData', 'test');
// Error: Argument of type 'string' is not assignable to parameter of type 'never'.
// Case 3: Multiple parameters with optional
const result1 = api.call('complexMethod', 1, 'test');
// Error: Argument of type 'number' is not assignable to parameter of type 'never'.
```
### 🙁 Actual behavior
TypeScript fails to correctly resolve method overloads when using generic mapped types with Parameters utility type:
1. Methods with NO parameters: TypeScript expects 2 arguments instead of matching the first overload `call(method: K)`
- Error: "Expected 2 arguments, but got 1"
2. Methods with OPTIONAL parameters: TypeScript cannot determine that optional parameters can be omitted
- Error: "Argument of type 'string' is not assignable to parameter of type 'never'"
3. The overload resolution always picks the second overload even when it shouldn't
The generic constraint with `Parameters` appears to confuse the overload resolution mechanism.
### 🙂 Expected behavior
The overload resolution should work correctly based on the number and types of arguments:
1. When calling `api.call('getString')` with no additional arguments, TypeScript should match the FIRST overload and return type `string`
2. When calling `api.call('processData', 'test')` with optional parameters omitted, it should be valid and infer the correct types
3. Optional parameters should be truly optional in the method call
The compiler should be able to:
- Distinguish between the two overloads based on argument count
- Properly handle optional parameters in generic contexts
- Correctly infer return types based on the matched overload
This pattern is essential for type-safe API wrappers, RPC clients, and plugin systems.
### Additional information about the issue
This issue significantly impacts developer experience when building type-safe wrappers around dynamic method collections.
**Real-world use cases affected:**
- GraphQL/REST client generators
- RPC frameworks (tRPC, JSON-RPC)
- Database ORMs with dynamic query methods
- Plugin architectures with registered methods
- Testing utilities for creating typed mocks
**Current workarounds (all suboptimal):**
1. Use type assertions (`as any`) - loses type safety
2. Avoid overloads entirely - poor API ergonomics
3. Create individual wrapper methods - defeats the purpose of generic approach
**Related issues:**
- #47607 - Generic inference with Parameters utility type
- #26591 - Overload resolution with generic constraints
- #20732 - Overload gets lost in mapped type with conditional type
Without proper overload resolution, library authors must sacrifice either type safety or developer experience.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
リンクされている TypeScript Playground の再現から始め、overload、Parameters、ReturnType、optional parameters に関係する失敗している 3 つの呼び出しを調査します。関連する issue #47607、#26591、#20732 と挙動を比較します。呼び出しが期待される引数の処理と推論された戻り値の型で型チェックを通り、compiler regression coverage によって裏付けられれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- typescript
- 領域
- compilers
- issue の種類
- バグ
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 30/100