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

Aperta
#61,176 1 commento 11 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Domain: check: Control Flow Help Wanted Possible Improvement
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

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. 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

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.