microsoft / microsoft/TypeScript

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

Ouverte
#23,226 8 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Awaiting More Feedback Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Reproduisez l’exemple avec TypeScript 2.9.0-dev ou le playground actuel, puis inspectez les chemins du checker mentionnés dans l’issue : isRelatedTo, recursiveTypeRelatedTo, indexTypesRelatedTo et isObjectTypeWithInferableIndex. Comparez la gestion de la compatibilité pour le type d’intersection et le type avec des signatures d’appel et d’index combinées ; le travail est terminé lorsque les deux affectations sont acceptées de manière cohérente sans affaiblir les vérifications non liées.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.