microsoft / microsoft/TypeScript
Narrow object property indexed by bracket notation when the key is a known literal type, regardless of where the key comes from
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ả
### 🔍 Search Terms
type guard, narrowing, control flow analysis, property, index, known type, literal type, bracket notation
### ✅ Viability Checklist
- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
### ⭐ Suggestion
This is a *different* re-opening or re-focusing of #10530, not the same as #56389, and was not fixed by #57847. The original motivating example for #10530 (treat `obj["key"]` like `obj.key` for narrowing) was fixed long ago, and more recently many of the remaining requests which had been added to #10530 were also fixed (narrowing for `obj[key]` when `key` is a variable whose literal type isn't known, for multiple uses of the same `key`). Those issues are closed. But it seems there are still some issues lumped in with #10530 which were not addressed, so here's the suggestion:
Please enable narrowing of object properties accessed via bracket notation based on the *type* of the key whenever the key's type is a known literal, even if multiple distinct variables or properties are used as keys. That is, if you have `key1` and `key2` and `keyObj.prop` and they are all of the literal type `"foo"` (or have been narrowed to that type), then treat `obj[key1]` and `obj[key2]` and `obj[keyObj.prop]` all as `obj.foo` for control flow purposes.
### 📃 Motivating Example
#51368 gives one, where the variable is a `let` variable annotated with a literal type or `const` asserted :
```ts
let k: "foo" = "foo";
// let k = "foo" as const; // <-- same behavior
const obj = { foo: Math.random() < 0.5 ? "abc" : undefined }
if (obj.foo) { obj[k].toUpperCase() } // error!
// ~~~~~~ possibly undefined
```
Probably I'd say someone should use a `const` there instead of `let`.
----
There's also one from [this Stack Overflow question](https://stackoverflow.com/questions/79438226/typescript-error-property-does-not-exist-on-type-with-optional-object-property), involving [`enum`-like `const`-asserted objects](https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums):
```ts
const Enum = { FOO: "foo", BAR: "bar" } as const;
const obj = { [Enum.FOO]: Math.random() < 0.5 ? "abc" : undefined }
if (obj[Enum.FOO]) obj[Enum.FOO].toUpperCase() // ERROR!
// ~~~~~~~~~~~~~ possibly undefined
```
This one strikes me as quite unfortunate, since an actual `enum` works just fine here:
```ts
enum Enum { FOO = "foo", BAR = "bar" }
const obj = { [Enum.FOO]: Math.random() < 0.5 ? "abc" : undefined }
if (obj[Enum.FOO]) obj[Enum.FOO].toUpperCase() // OKAY
```
### 💻 Use Cases
1. What do you want to use this for?
See #10530 and various issues closed as duplicates for more use cases.
2. Current approaches and workarounds:
If TS knows the literal key then you do too, so you could always just use it directly:
```ts
const Enum = { FOO: "foo", BAR: "bar" } as const;
const obj = { [Enum.FOO]: Math.random() < 0.5 ? "abc" : undefined }
if (obj.foo) obj.foo.toUpperCase() // OKAY
```
That's reasonable, but I think it would be nice if there weren't this caveat for `enum`-like objects where you can't actually use them as keys directly for narrowing purposes.
[Playground link to code](https://www.typescriptlang.org/play/?ts=5.7.3#code/FAOwhgtgpgzgDmAxlABAQRCA9gFzDqAEwBkocUBvYFGlAGzJQGsAuFAIgDMst2UBeDt14BuarURYQMclgBGAKwGUUwtgFl8ACwB0AJzAhCWCAAoAlCgA8KAAw6ArCgD8HMHMR82AVyNROAJYgRCgAvuI0AZwopvIKOsKWFChxANpMALo6OFgAqnBwUHoAwmAwUBZhKAD01ShFelh6AIQRNXW0nV0Afr19KHBYMDABcnQAnii+hP5BRMDA4aCQsAjIKMVSMmjDRQQkjFSdDORMylw8fGUoktI4Yp23MimKyslqKJo4ugZGJpU2exOVzsdyeFA+PyBYKEMJtKIxOIJHhJF4KdJZHL5QolMoVSyhdr1PSNFptWpdSk0Pr9QbDUYTKZQuaERYLcDQeBIVAAURA3ggdACTFQRwkW3IfIFbxQADEAPLytgXXgAGhQACE0AAlZVyMB6PiE65Pe5tU1omWpKUQHQK+UZDTafSGYxmSyAxwuNweLxMmbQkLhToI2KKa38232jKWNI2u2KzF5ApFUrlSoUnna7Xy7WtToUqlFlA00s0gZDEZjSbTWYwtnslZc9YAFT03igNsobSgkZQXeS9vOwnY6q12vO+sNcMeEstgmSEYFCYdTu+Lr+7usdi9ILBftrgdhwdoobjkZXMbRS6jieyyZxafxRPlAGk0ABNBvLTlrVAAdSaJgDSwaZu1nO5+z7Bc5UVZURzHHU9QNI0UBNCUHnFSC4iteNozXH5XX+D0d2BH1wUhAMWRnU9ojDeJEjRZEsHvbFUzxDM6jfT8GyAA)
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 ví dụ TypeScript Playground được liên kết và so sánh hành vi còn lại với các issue #10530, #56389 và #57847. Kết quả mong muốn là các truy cập bằng dấu ngoặc vuông có các khóa cùng kiểu literal đã biết được narrow giống như truy cập thuộc tính bằng dấu chấm, bao gồm khóa `let` và các ví dụ đối tượng `const` giống enum; không có tệp triển khai hoặc bài kiểm thử nào được nêu tên.
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
- Tính năng
- Độ 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
- 35/100