microsoft / microsoft/TypeScript

Cant infer type of parent based on member of child

Ouverte
#31,608 1 commentaire 9 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

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

Description

TypeScript Version: 3.4.5

Search Terms:

  • infer parent based on child
  • type inference in if statement
  • conditional generic type infer

Code

const enum ChildType {
    A,
    B,
    C
}

interface ChildrenMap {
    [ChildType.A]: { value: 10 },
    [ChildType.B]: { value: string },
    [ChildType.C]: { value: boolean, test?: boolean }
};

// Create a "Child", that has a type and
// other members based on what type it is
type Child<T extends ChildType> = { type: T } & ChildrenMap[T];

interface ParentMap {
    [ChildType.A]: { color: 'red' },
    [ChildType.B]: { color: 'blue' },
    [ChildType.C]: { color: 'green' }
}

// Create a "Parent", that has a "Child", which
// has a type, which decides what members the 
// parent should have
type Parent<T extends Child<any>> =
    T extends Child<infer R>
    ? R extends ChildType ? ParentMap[R] & { child: Child<R> }
    : never 
    : never;

// More of the same stuff!
interface GrandParent<T extends Parent<Child<any>>> {
    parent: T extends Parent<Child<infer R>>
    ? R extends ChildType ? Parent<Child<R>>
    : never
    : never; 
}

// It all works as expected at this point
let A: Parent<Child<ChildType.A>>;
let red: typeof A['color'] = 'red';
let justRed: typeof A['color'] = 'blue'; // error!

// Same sorta thing as ^
let B: Parent<Child<ChildType.B>>;
let C: Parent<Child<ChildType.C>>;

function testParent<T extends Parent<any>>(parent: T) {
    if (parent.child.type === ChildType.A) {
        parent.child.value; // equals 10!
        parent.color; // red | green | blue, but should only be red
    }
}

function testGrandParent<T extends GrandParent<any>>(grandParent: T) {
    if (grandParent.parent.child.type === ChildType.B) {
        grandParent.parent.child.value; // string, yay!
        grandParent.parent.color; // red | green | blue, but should only be blue
    }
}

Expected behavior:
As the type of "Child" is being set using the same conditional type as the parent, the parent type should also get the appropriate type for "color".
In the case of testParent, the statement parent.type === ChildType.A correctly infers the value of value (in the case of that example 10). This should also happen for the top level member "color" as well (in the case of that example, color should be set to "red").

Actual behavior:
parent.child.type and parent.child.value, correctly coerce the appropriate type. However color is incorrect "red" | "blue" | "green" instead of one of the three.

Playground Link:

link to the playground

Related Issues:

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

Commencez par la reproduction liée dans Playground et les exemples testParent et testGrandParent, puis comparez le comportement avec typescript@next. La modification est terminée lorsque le rétrécissement de parent.child.type rétrécit également la couleur du parent conteneur vers le literal correspondant dans les deux exemples, et qu'une couverture de régression a été ajoutée à la suite de tests du compilateur.

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é
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

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