microsoft / microsoft/TypeScript

Need a dummy overload to improve inference

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

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

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

説明

TypeScript Version: 3.x, 4.0.0-beta, nightly

Search Terms: dummy fake overload infer

Code

class FieldEvent<T extends Field> {
    constructor(readonly field: T, readonly message: string) { }
}

class Field {
    listen<T extends FieldEvent<Field>>(type: new (...args: any[]) => T, listener: (event: T) => void): void { }
}

class BeforeSetEvent<T extends number | string> extends FieldEvent<ValueField<T>> {
    constructor(field: ValueField<T>, public newValue: T) { super(field, ""); }
}

class AfterSetEvent<T extends number | string> extends FieldEvent<ValueField<T>> {
    constructor(field: ValueField<T>, readonly oldValue: T) { super(field, ""); }
}

class ValueField<T extends number | string> extends Field {
    constructor(public value: T) { super(); }

    // listen<U extends FieldEvent<Field>>(type: new (arg: this) => U, listener: (event: U) => void): void;
    // listen<U extends FieldEvent<Field>>(type: new (...args: any[]) => U, listener: (event: U) => void): void;
    listen<U extends FieldEvent<Field>>(type: new (...args: any[]) => U, listener: (event: U) => void): void {
        super.listen(type, listener);
    }
}

let field = new ValueField(0);
field.listen(FieldEvent, (event) => event.field);                           // event: FieldEvent<any>
field.listen(BeforeSetEvent, (event) => { event.field; event.newValue; });  // event: BeforeSetEvent<any>
field.listen(AfterSetEvent, (event) => { event.field; event.oldValue; });   // event: AfterSetEvent<any>

Expected behavior:
event to be better inferred than any.

Actual behavior:
event inferred as any.

But if we uncomment the 2 overloads, then event is correctly inferred:

field.listen(FieldEvent, (event) => event.field);                           // event: FieldEvent<ValueField<0>>
field.listen(BeforeSetEvent, (event) => { event.field; event.newValue; });  // event: BeforeSetEvent<0>
field.listen(AfterSetEvent, (event) => { event.field; event.oldValue; });   // event: AfterSetEvent<0>

What's surprising (so the reason I consider it as a bug):

  • The 1st overload doesn't match any signature.
  • But it influences the way the other overload is inferred.

Note that if we replace (arg: this) by () or another type, then:

field.listen(FieldEvent, (event) => event.field);                           // event: FieldEvent<Field>
field.listen(BeforeSetEvent, (event) => { event.field; event.newValue; });  // event: BeforeSetEvent<string | number>
field.listen(AfterSetEvent, (event) => { event.field; event.oldValue; });   // event: AfterSetEvent<string | number>

Playground Link: Playground Link

Related Issues: I first posted #36226 but was not able to solve my issue, until I found the (arg: this) trick.

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

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

はじめの一歩

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

調査の方向性

リンク先の TypeScript Playground の例をまず再現し、2 つのオーバーロードがある場合とない場合で推論を比較します。listen 呼び出しに対するコンパイラのジェネリック推論とオーバーロード解決の動作を追跡します。ダミーのオーバーロードなしで、コールバックから FieldEvent、BeforeSetEvent、AfterSetEvent が関連する具体的な型とともに推論されれば完了です。

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

評価

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

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

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