microsoft / microsoft/TypeScript

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

オープン
#37,465 コメント 0 件 リアクション 5 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Awaiting More Feedback Suggestion
主要言語
Go
スター
111k
フォーク
14.4k
平均マージ
1日 19時間
マージ済み PR(30日)
117

説明

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
}

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

リンクされている TypeScript Playground の例から始め、string、object、および不可能な typeof チェックについて、現在の絞り込み結果を要求された結果と比較します。完了条件は、判別共用体の値が適切なメンバーに、または不可能なケースでは never に絞り込まれることです。動的キーと明示的プロパティの例も含みます。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
typescript
領域
compilers
issue の種類
機能追加
難易度
5/5
見積もり時間
1週間以上
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。