microsoft / microsoft/TypeScript

Method overloads fail to resolve correctly when using mapped types with conditional generics and optional parameters

Đang mở
#62,377 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Needs More Info
Ngôn ngữ chính
Go
Star
111k
Fork
14.3k
Merge trung bình
2 ngày 4 giờ
Pull request đã merge (30 ngày)
132

Mô tả

🔎 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
// Minimal reproduction showing the bug
class API<T extends Record<string, (...args: any[]) => any>> {
  constructor(private methods: T) {}
  
  // Method overloads for better DX
  call<K extends keyof T>(method: K): ReturnType<T[K]>;
  call<K extends keyof T>(method: K, ...args: Parameters<T[K]>): ReturnType<T[K]>;
  call<K extends keyof T>(method: K, ...args: any[]): ReturnType<T[K]> {
    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<T[K]> utility type:

  1. Methods with NO parameters: TypeScript expects 2 arguments instead of matching the first overload call<K>(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<T[K]> 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với bản tái hiện được liên kết trên TypeScript Playground và kiểm tra ba lời gọi bị lỗi liên quan đến overload, Parameters, ReturnType và các tham số tùy chọn. So sánh hành vi với các issue liên quan #47607, #26591 và #20732; được xem là hoàn tất khi các lời gọi được kiểm tra kiểu với cách xử lý đối số như mong đợi và các kiểu trả về được suy luận như mong đợi, có kiểm thử hồi quy của compiler để đảm bảo.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
typescript
Lĩnh vực
compilers
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
30/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.