microsoft / microsoft/TypeScript

Inconsistent type compatibility for a type with a call signature and and index signature

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

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

Awaiting More Feedback Suggestion
主要言語
Go
スター
111k
フォーク
14.3k
平均マージ
2日 4時間
マージ済み PR(30日)
132

説明

TypeScript Version: 2.9.0-dev

Search Terms: index signature intersection

Code

type INOk = {
    (): string;
    [name: string] : number;
}

type IOk = {
    (): string;
} & {
    [name: string] : number;
}

declare let val:(() => "") & { foo: number; }
let ok: IOk = val; // This works
let nok: INOk = val; // This does not

Expected behavior:
Both IOk and INOk have the same public structure, they both have a call signature and are indexable, both assign statements should be valid.

Actual behavior:
The second assign statement fails with the message Index signature is missing in type '(() => "") & { foo: number; }'.

Playground Link: link
Related Issues: https://github.com/Microsoft/TypeScript/issues/15300

Notes
Looking at the checker code, it appears that for IOk type compatibility is checked for each constituent of the intersection type, so we will have :

isRelatedTo (typeof val, IOk) = 
      isRealtedTo(typeof val, () => ""))   // == True, since val has a call signature
             ( // Above equal to 
                   isRelatedTo(() => "", () => "") // ==  True
                   ||
                   isRelatedTo({ foo: number; }, () => "") // == False but it's does not matter
             )
      &&
      isRealtedTo(typeof val, { [name: string] : number }) // = True since the { foo: number} part of typeof val has an inferable index (ie isObjectTypeWithInferableIndex( { foo: number} ) will return true)
            ( // Above equal to 
                   isRelatedTo(() => "",  { [name: string] : number }) // ==  False but does not matter
                   ||
                   isRelatedTo({ foo: number; },  { [name: string] : number }) // == True, 
             )

While for INOk the relation is checked directly, since INOk can't be split into constituents and we have

isRelatedTo (typeof val, INOk) = 
              isRelatedTo(() => "",  INOk) // ==  False INOk has index, but ()=> "" does not
              ||
              isRelatedTo({ foo: number; },  INOk) // == False, No compatible call signature

So then the checker falls back to structural checking (recursiveTypeRelatedTo) but this fails as well because when checking for index compatibility (inside indexTypesRelatedTo), it decides that the typeof value ((() => "") & { foo: number; }) does not have an inferable index (isObjectTypeWithInferableIndex returns false because the intersection type does not have a symbol and even if it did the condition for inferable index checks that the type does not have a call signature (!typeHasCallOrConstructSignatures(type)))

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

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

はじめの一歩

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

調査の方向性

TypeScript 2.9.0-dev または現在の playground で例を再現し、その後、issue で指定されている checker のパスを調べます: isRelatedTo、recursiveTypeRelatedTo、indexTypesRelatedTo、isObjectTypeWithInferableIndex。交差型と、呼び出しシグネチャおよびインデックスシグネチャを組み合わせた型について、互換性の扱いを比較します。完了の条件は、無関係なチェックを弱めることなく、両方の代入が一貫して受け入れられることです。

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

評価

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

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

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