microsoft / microsoft/TypeScript

Dynamic object key + discriminated union + typeof could have a better narrowing type

Aperta
#37,465 0 commenti 5 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Awaiting More Feedback Suggestion
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
2g 4h
PR unite (30g)
132

Descrizione

Search Terms

dynamic object key, discriminated union, typeof, type inference, narrowing type

Suggestion (or is it a bug report?)

We could write a discriminated union with one of the cases is a dynamic object key. For example...

type TExample = (
  {
    [key in string]: {
      foo: number
    }
  }
  | {
    errorCode: string
  }
)

So, if the key is errorCode it could be a { foo: number } or a string. If the key is any string that isn't errorCode, it should be a { foo: number }.

Then let's check that.

const func: () => TExample = () => ... // get value from somewhere

const value = func()

if ('errorCode' in value && typeof value.errorCode === 'string') {
  value // what's the type of value here?
}

So, makes sense that the value's type should be { errorCode: string }, right?
But the type still is TExample! I think that we could have a better narrowing type, because value only shoud be { errorCode: string } on this case.

Similarly, would be nice to have that:

if ('errorCode' in value && typeof value.errorCode === 'object') {
  value // should be { [key in string]: { foo: number } }
}

As well as...

if ('errorCode' in value && typeof value.errorCode === 'number') {
    value // should be never
}

Full code on playground

Edit

I just noticed that it happens even when we are not using a dynamic object key...

type TExample = (
  {
    aaa: {
        foo: number
    }
  }
  | {
    errorCode: string
  }
)

const func: () => TExample = () => ... // get value from somewhere

const value = func()

if ('errorCode' in value && ((typeof value.errorCode) === 'number')) {
    value // type is "{ errorCode: string }" ......  what!? I think that the expected is to be "never"
}

Playground

Use Cases

I'm opening this issue because I had a problem because of this limitation.

I'm developing a client for an API and, for convention, all errors is returned as { errorCode: string }.
And on an endpoint, the json can be a { [key in string]: TComplexObject } on success case, or be a { errorCode: string } on fail case.
So normally I'm checking if I had an error using if ('errorCode' in result) {, but on this endpoint it isn't enough since we have this limitation on TS. Then I don't have a good type inference on this case, needing to write a more complex code.

Examples

type TExample = (
  {
    [key in string]: {
      foo: number
    }
  }
  | {
    errorCode: string
  }
)

const func: () => TExample = () => ({ blah: { foo: 1 } })

const value = func()

if ('errorCode' in value && typeof value.errorCode === 'string') {
  value // should be { errorCode: string }
}

if ('errorCode' in value && typeof value.errorCode === 'object') {
  value // should be { [key in string]: { foo: number } }
}

if ('errorCode' in value && typeof value.errorCode === 'number') {
  value // should be never
}

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 dagli esempi collegati di TypeScript Playground e confronta i risultati attuali del narrowing con i risultati richiesti per i controlli string, object e typeof impossibili. L'attività è completata quando il valore della discriminated union viene ristretto al membro appropriato, oppure a never nel caso impossibile, inclusi gli esempi con chiave dinamica e proprietà esplicita.

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.