Strange behavior of types while using nested mapped types and generics

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

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

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
停滞
技術スタック
typescript
領域
compilers

調査の方向性

提供された TypeScript Playground のリンクとネストされたオブジェクトビルダーの例から始め、test に推論される型を、単独の n および p の宣言と比較します。ネストされたジェネリック呼び出しが OptionalyProped 型をどのように推論するかを追跡します。ネストされた n プロパティが一貫して OptionalyProped<number> に推論され、p プロパティが OptionalyProped<21> を保持すれば完了です。

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

説明

Needs Investigation

Bug Report

I got two differents typings while nesting objects using some object-builder functions and generic optional typings, keeping it quite basic.

These two typings show up in a one-in-two pattern as we dig into the nested objects.
The second one matches with the type of the object-builder.

It can be a misuse of mine so let me know ...

🔎 Search Terms
  • mapped type
  • nested
  • partial optional
  • generic
🕗 Version & Regression Information

Typescript versions 5.1.4 & 5.2.0-dev.20230625 & 4.1.6

Just discovered it, so AFAIK this is not a regression.

⏯ Playground Link

Just here

💻 Code
type OptionalyProped<OPTL extends number> = { optlValue?: OPTL }
export const optionalyProped = <OPTL extends number>(proped: OptionalyProped<OPTL>): OptionalyProped<OPTL> => proped


type ObjectOfProped<T extends { [key: string]: ObjectOrProped }> = { structure: T }
export const objectOfProped = <OBJ extends { [key: string]: ObjectOrProped }>(
    objectOf: ObjectOfProped<OBJ>
    ): ObjectOfProped<OBJ> => objectOf

type ObjectOrProped = ObjectOfProped<any> | OptionalyProped<any>

const test = objectOfProped({
	structure: {
		n: optionalyProped({}),
                p: optionalyProped({ optlValue: 21}),
		o: objectOfProped({
			structure: {
				n: optionalyProped({}),
                                p: optionalyProped({ optlValue: 21}),
				o: objectOfProped({
					structure: {
						n: optionalyProped({}),
                                                p: optionalyProped({ optlValue: 21}),
						o: objectOfProped({
							structure: {
								n: optionalyProped({}),
                                                                p: optionalyProped({ optlValue: 21}),
							},
						}),
					},
				}),
			},
		}),
	},
})

const n = optionalyProped({ }) // typed: OptionalyProped<number>
const p = optionalyProped({ optlValue: 21 }) // typed: OptionalyProped<21>

🙁 Actual behavior
typeof test = ObjectOfProped<{
    n: OptionalyProped<any>;                // first behavior
    p: OptionalyProped<number>;
    o: ObjectOfProped<{
        n: OptionalyProped<number>;         // second behavior (legit one)
        p: OptionalyProped<21>;
        o: ObjectOfProped<{
            n: OptionalyProped<any>;
            p: OptionalyProped<number>;
            o: ObjectOfProped<{
                n: OptionalyProped<number>;
                p: OptionalyProped<21>;
            }>;
        }>;
    }>;
}>
🙂 Expected behavior
typeof test = ObjectOfProped<{
    n: OptionalyProped<number>;             // always
    p: OptionalyProped<21>;
    o: ObjectOfProped<{
        n: OptionalyProped<number>;         // the same
        p: OptionalyProped<21>;
        o: ObjectOfProped<{
            n: OptionalyProped<number>;     // type
            p: OptionalyProped<21>;
            o: ObjectOfProped<{
                n: OptionalyProped<number>;
                p: OptionalyProped<21>;
            }>;
        }>;
    }>;
}>

Thanks

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

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

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

はじめの一歩

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

microsoft/TypeScript のほかの issue

microsoft/TypeScript の issue をすべて見る

似ている issue

Go の issue をもっと見る

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

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