Intersection of merged declarations - function types behave inconsistently
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 停滞
- 技術スタック
- typescript
- 領域
- compilers
調査の方向性
まず、リンク先の TypeScript Playground の再現コードを実行し、マージされた Foo と Bar の宣言を union の呼び出し動作と比較します。次に、関連する issue #19064 の議論を読み、マージされた関数型と union を担当する型チェックの経路を追跡します。union の呼び出し結果と ReturnType が一致し、固有の shuffle メソッドが維持されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
🔎 Search Terms
declaration merging
🕗 Version & Regression Information
- This is a type inference problem
- This problem appears in Typescript 3.3.3, 3.5.1, 3.9.7, 4.9.5, 5.3.3 and 5.4.0-dev.20240207
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about declaration merging
⏯ Playground Link
💻 Code
type MyArrayExtension<T> = Array<T> & { shuffle(): void }
interface Foo { getList(): Array<string> }
interface Foo { getList(): MyArrayExtension<string> }
interface Bar { getList(): Array<string> }
interface Bar { getList(): MyArrayExtension<string> }
type FooListType = ReturnType<Foo["getList"]> // as expected: string[] & {shuffle(): void;}
type BarListType = ReturnType<Bar["getList"]> // as expected: string[] & {shuffle(): void;}
type FarListType = ReturnType<(Foo|Bar)["getList"]> // as expected: string[] & {shuffle(): void;}
let fooFn = ({} as Foo).getList; // { (): Array<string>; (): MyArrayExtension<string>; }
let barFn = ({} as Bar).getList; // { (): Array<string>; (): MyArrayExtension<string>; }
let farFn = ({} as Foo|Bar).getList; // { (): Array<string>; (): MyArrayExtension<string>; } | { (): Array<string>; (): MyArrayExtension<string>; }
let farList: FarListType = farFn(); // should work, but error:
/*
Type 'string[]' is not assignable to type 'MyArrayExtension<string>'.
Property 'shuffle' is missing in type 'string[]' but required in type '{ shuffle(): void; }'.(2322)
*/
({} as Foo).getList().shuffle(); // works
({} as Bar).getList().shuffle(); // works
({} as Foo|Bar).getList().shuffle(); // Error: Property 'shuffle' does not exist on type 'string[]'.(2339)
🙁 Actual behavior
There are two interfaces (Foo and Bar), that each are constituted of two merged declarations.
Each interface individually behaves such that the later declaration wins (getList(): MyArrayExtension<string> in either case). When changing the order (define the MyArrayExtension returning interfaces first), the return type accordingly is string[].
However, when intersecting Foo|Bar, the behaviour becomes inconsistent:
ReturnType<(Foo|Bar)["getList"]>is what I would expect (compatible withMyArrayExtension<string>), but({} as Foo|Bar).getList()is not assignable to a variable of this type
🙂 Expected behavior
My use case is the following: I have an external dependency that defines interfaces with functions that return T[].
Since I know those functions return a specific type that extends T[], I want to augment the module (using declare module) and give the functions a more specific return type.
The behaviour for non-intersected types if perfect for this. The later (e.g. provided by my declare module augmentation) wins.
However, it breaks down when intersecting two types from the external dependency, as described above.
I would expect type inference to work consistently. I think it's good to be able to override/make types more specific this way, and I think this ability should not be lost when intersecting types for which this has been done.
Additional information about the issue
@jcalz explained to me on StackOverflow that this problem is not restricted to module augmentation, but appears even when merging declarations in the same file. The problem is probably related to #19064.
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.4k
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 106
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/TypeScript のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
microsoft/TypeScript#64322 · コメント 2 件 · リアクション 1 件 · 担当者 2 名 ·
-
Possible Improvement
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
microsoft/TypeScript#64278 · コメント 1 件 · リアクション 1 件 ·
-
Docs
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
microsoft/TypeScript#64118 · コメント 1 件 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
microsoft/TypeScript#64094 ·
-
Docs
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
microsoft/TypeScript#63959 · コメント 5 件 ·
microsoft/TypeScript の issue をすべて見る
似ている issue
-
Type/Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
OpenNSW/nsw-srilanka#497 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 92/100
milvus-io/birdwatcher#545 ·
-
kind/bug
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
kubernetes-sigs/prow#953 · コメント 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
caddyserver/caddy#8046 ·