microsoft / microsoft/TypeScript

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

Aperta
#23,226 8 commenti 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Awaiting More Feedback Suggestion
Lingua principale
Go
Stelle
111k
Fork
14.4k
Merge medio
1g 19h
PR unite (30g)
117

Descrizione

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)))

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Riproduci l’esempio con TypeScript 2.9.0-dev o con il playground attuale, quindi analizza i percorsi del checker indicati nell’issue: isRelatedTo, recursiveTypeRelatedTo, indexTypesRelatedTo e isObjectTypeWithInferableIndex. Confronta la gestione della compatibilità per il tipo intersezione e per il tipo con firme di chiamata e di indice combinate; il lavoro è completo quando entrambe le assegnazioni vengono accettate in modo coerente senza indebolire i controlli non correlati.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
typescript
Ambito
compilers
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.