microsoft / microsoft/TypeScript

Explicit target type breaks generic parameter inference for function call with intersection return type

Đang mở
#61,467 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
Domain: check: Type Inference Help Wanted Possible Improvement
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

explicit target type breaks generic parameter inference function call intersection return type contextual typing

### 🕗 Version & Regression Information

- This is the behavior in every version I tried, and I reviewed the FAQ for entries about "explicit"

### ⏯ Playground Link

https://www.typescriptlang.org/play/?strictBuiltinIteratorReturn=true#code/GYVwdgxgLglg9mABMAjAHgIKIKYA8rZgAmAzogNbYCecwiAEgCoCyAMgKIA22AtoVIwCGAcwBygvs0EAHADSIAQgD4AFIIBciDPIBGmhQEpNTNl178hYidinSA2hgC6iAGSLEAbwCwAKESIAJ2woEACkAHkdACtsaAA6QRISGGEwFSI4CBA+MCg4iCDBAjMcqDUDXQMAbl8AX19QSFgEZAAmTBx8QlJPWvllNU1tRD1FIy1Xd28-QODQiOjYvMTk1LVKmp96n18Ael3ERgALGDJgQRhOMh1YwRASbEOAZUQYMGBsALIFRABeBhYrAUICgUAQJX4kw8CAgnBgEHImhUBj+SkQADc4DAiLVXmASARBERELR3P9oZA4QikSjfmjMdjthAEATEAQCShjIDgaDwdxSlCYVTEYhkaiMVicX9kCgVAAiHQgsFgOXyCmw+EixrQeBpAweWq1ap7A7HU6IADucAC5DI2HRhDZRzgIGERydjzeHwCQWJUCo0k9ZCgR0eJGsiESHs60ipMCgbIDj0EOjgDt8zPxCfZUFa-nzBcLReLJdL-1Q8sVvJVaqFms02uaeoNRs2+0OJzIVpt11u90ewkIn3hiGkggC1gIX0jQUQwhgDqQeFj8PjnCoGZZ2ewBIAzFy2DzlRDcoLKfXRbT6ZLceX0AqlQhVZ469TL+KGTjVA-q8-1cKG3AHUEGRFtjR8dszS7a1bRGPsHhnAI4AtZAgKbMhx0eMA4ATQRgA+aBsGJYBrUQEg4D4WZEgQTcszZHcoAAFgPIFHzAE8Ezcf8LzFOkJUZaUKx-ZU-1fEVeLRMC21NTtLRg3sIDuBCvU+QgIEebtYJuUFPkteNnRBRNA0QHgZFo1kcwAVhYo8+XMU8uLEmkPxvQTWnSTJsn4fJCmKfl+ErNi5QqF9zzfRtdVAw1wKAA

### 💻 Code

```ts
function f1(a: A, b: B): HTMLElementTagNameMap[A] & B {
return Object.assign(document.createElement(a), b);
}
function f2
(a: A, b: B): A & B {
return Object.assign(a, b);
}

// This fails because TS infers B = HTMLButtonElement & {onclick: () => void} instead of B = {onclick: () => void}
const test1: HTMLButtonElement & {onclick: () => void} = f1("button", {onclick: function(){}});
// This works even though the inferred type is the same as the explicit type above
const test2 = f1("button", {onclick: function(){}});
// This works because generic parameters are given explicitly
const test3: HTMLButtonElement & {onclick: () => void} = f1<"button", {onclick: () => void}>("button", {onclick: function(){}});
// This works because arrow functions are not affected for some reason
const test4: HTMLButtonElement & {onclick: () => void} = f1("button", {onclick: () => {}});
// This works because inference works better without type map
const test5: HTMLButtonElement & {onclick: () => void} = f2(document.createElement("button"), {onclick: function(){}});
```

### 🙁 Actual behavior

`test1` shows an error:
> Argument of type '{ onclick: (this: GlobalEventHandlers) => void; }' is not assignable to parameter of type 'HTMLButtonElement & { onclick: () => void; }'.

This is because TS sees that `test1` is explicitly typed `HTMLButtonElement & {onclick: () => void}`, and so it erroneously infers the generic type parameters of `f1` as `B = HTMLButtonElement & {onclick: () => void}`, even though the correct inference is `B = {onclick: () => void}`.

More interestingly, `B` is inferred correctly if the explicit target type is omitted, as demonstrated with `test2`. However, the inferred type of `test2` is the same as the explicit type of `test1`!

### 🙂 Expected behavior

If a program is valid with an inferred type, then it should also be valid when that type is turned explicit.

### Additional information about the issue

The code snippet also demonstrates that this issue is somehow related to using mapped types and `function(){}` instead of `() => {}`. While curious, I think the main issue is that `test1` and `test2` behave differently.

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

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

Hướng nghiên cứu

Bắt đầu với bản tái hiện TypeScript Playground được liên kết và so sánh test1 đến test5, tập trung vào việc suy luận tham số generic cho f1 và kiểu trả về giao của nó. Truy vết hành vi của checker chịu trách nhiệm về việc định kiểu theo ngữ cảnh cho function(){}, sau đó sử dụng các ví dụ đã được báo cáo làm các trường hợp hồi quy. Được xem là hoàn tất khi test1 được chấp nhận nhất quán cùng với test2 mà không làm hỏng các trường hợp suy luận khác.

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.