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
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.3k
- Merge medio
- 2g 4h
- PR unite (30g)
- 132
Descrizione
### 🔍 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)
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con l’esempio collegato di TypeScript Playground e confronta il comportamento rimanente con le issue #10530, #56389 e #57847. Il risultato desiderato è che gli accessi con parentesi quadre le cui chiavi hanno lo stesso tipo letterale noto vengano ristretti come gli accessi alle proprietà con la notazione a punto, inclusi la chiave `let` e gli esempi di oggetti `const` simili a enum; non vengono indicati file di implementazione né test.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100