Typescript: Impossible d'attribuer une valeur compatible à une propriété typée générique à l'aide de «extend» dans la définition générique.

Créé le 7 avr. 2017  ·  3Commentaires  ·  Source: microsoft/TypeScript

Version TypeScript: 2.2.2

Je ne comprends peut-être pas comment fonctionnent les génériques (si c'est le cas, indiquez-moi la bonne direction), mais cela semble être un bogue.

Code

// A *self-contained* demonstration of the problem follows...

interface BaseState {
    on: boolean;
};

class Component {
    state: BaseState;

    setState(state: BaseState) {
        this.state = state;
    }

    onInput({ value }: { value: number }) {
        this.setState({ on: value > 0 });  // no error
    }
}

class GenericComponent<State extends BaseState> {
    state: State;

    setState(state: State) {
        this.state = state
    }

    onInput({ value }: { value: number }) {
        this.setState({ on: value > 0 });  // error Argument of type '{ on: boolean; }' is not assignable to parameter of type 'State'.
    }
}

Comportement attendu:
Dans la classe Component de l'exemple ci-dessus ne provoque aucune erreur lors de l'utilisation directe de l'interface BaseState . J'attends le même comportement de la classe GenericComponent puisque le générique State étend explicitement BaseState .

Comportement réel:
Au lieu de cela, j'obtiens l'erreur suivante liée à this.setState({ on: value > 0 }); : "L'argument de type '{on: boolean;}' n'est pas assignable au paramètre de type 'State'."

Question

Commentaire le plus utile

Considérez ce qui se passe si vous écrivez ceci

var t = new GenericComponent<{on: boolean, thing: string}>();
t.onInput({ value: 30 });
t.state.thing.substr(0); // 'thing' property should exist, but doesn't

Tous les 3 commentaires

Considérez ce qui se passe si vous écrivez ceci

var t = new GenericComponent<{on: boolean, thing: string}>();
t.onInput({ value: 30 });
t.state.thing.substr(0); // 'thing' property should exist, but doesn't

Voici un exemple simplifié:

class Stateful<State extends { on: boolean }> {
  state: State = {
    on: true
  }; // error
}

La raison pour laquelle cela ne fonctionne pas est qu'il ne sera valide que lorsque Stateful est instancié avec un argument de type exactement équivalent à { on: boolean } .

Fondamentalement, _il existe_ un type T , satisfaisant les contraintes de l'argument de type de Stateful tel que l'instanciation est valide mais cela ne tient pas _pour tous_ les types TT satisfait la contrainte de l'argument de type de Stateful .

Ainsi, le code errant ci-dessus affirme que, pour tous les types T<T>T, Stateful».

Logiquement, on peut le regarder comme suit

Affirmation

  1. Soit P le type { on: boolean }
  2. Pour tous les types T tels que T est assignable à P , la définition de Stateful<T> ci-dessus est valide

Démontrer par un contre-exemple

  1. Soit U le type { on: boolean, value: number }
  2. U est assignable à P -> par définition
  3. Stateful<U> n'est pas valide -> par substitution
  4. Il existe donc un type T tel que T est assignable à P et Stateful<T> est une instanciation invalide -> par implication

@RyanCavanaugh @aluanhaddad Shoot, je le savais. Je suis juste devenu confus en essayant de ramener le problème à quelque chose de plus simple. Alors essayons à nouveau. Qu'en est-il dans ce cas en utilisant un Partiel? J'obtiens toujours une erreur similaire.

interface BaseState {
    on: boolean;
};

class Component {
    state: BaseState;

    setState(partialState: Partial<BaseState>) {
        this.state = { ...this.state, ...partialState };
    }

    onInput({ value }: { value: number }) {
        this.setState({ on: value > 0 });  // no error
    }
}

class GenericComponent<State extends BaseState> {
    state: State;

    setState(partialState: Partial<State>) {
        this.state = { ...this.state, ...partialState };
    }

    onInput({ value }: { value: number }) {
        this.setState({ on: value > 0 });  // error: Argument of type '{ on: boolean; }' is not assignable to parameter of type 'Partial<State>'
    }
}
Cette page vous a été utile?
0 / 5 - 0 notes