microsoft / microsoft/TypeScript
Generic type unnarrowed by `switch...case`
Chưa có ai nhận issue này.
- 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ả
Bug Report
🔎 Search Terms
- narrowing of generic types
- exhaustive switch case
🕗 Version & Regression Information
Theoretically this should be fixed by:
- https://github.com/microsoft/TypeScript/issues/13995
- https://github.com/microsoft/TypeScript/pull/43183
Similar issue:
I'm trying against the latest beta: 4.3.0-pr-43183-11 / 15fae38b39a370f1f597606e552dd40998a1ac49.
⏯ Playground Link
Playground link with relevant code
💻 Code
interface TopLevelElementMap {
"a": HTMLElement;
"b": HTMLElement;
}
interface ElementAttributes {}
interface ElementAttributesMap {
"a": ElementAttributes;
"b": ElementAttributes;
}
class Element<TagName extends keyof TopLevelElementMap> {
protected attributes: ElementAttributesMap[TagName] = {};
public constructor(type: TagName) {}
}
const ElementTagNameMap = {
"a": function(): Element<"a"> {
return new Element("a");
},
"b": function(): Element<"b"> {
return new Element("b");
}
};
function createPrimitive<TagName extends keyof typeof ElementTagNameMap>(tagName: TagName) {
switch (tagName) {
case "a":
return function(): Element<TagName> {
//
// [?] Shouldn't `tagName` get narrowed to just "a"?
//
return ElementTagNameMap[tagName]();
};
case "b":
default:
throw new Error("Unrecognized element `" + tagName + "`.");
}
}
const a = createPrimitive("a");
const b = createPrimitive("b");
As a workaround I can assert as Element<TagName> on the inner-most return statement to silence the error.
🙁 Actual behavior
Type 'Element<"a"> | Element<"b">' is not assignable to type 'Element<TagName>'.
Type 'Element<"a">' is not assignable to type 'Element<TagName>'.
Type '"a"' is not assignable to type 'TagName'.
'"a"' is assignable to the constraint of type 'TagName', but 'TagName' could be instantiated with a different subtype of constraint '"a" | "b"'. (2322)
🙂 Expected behavior
TagName should be narrowed to one of the possible values dictated by the case clause.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- 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 TypeScript Playground được liên kết và xác nhận lỗi đã báo cáo trên giá trị trả về generic bên trong case của switch. Truy vết quá trình narrowing kiểu generic của trình biên dịch cho các mệnh đề switch, sau đó thêm coverage hồi quy cho thấy case thu hẹp TagName và đoạn mã mong đợi được kiểm tra kiểu mà không cần assertion.
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ó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 38/100