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'."
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 T
où T
satisfait la contrainte de l'argument de type de Stateful
.
Ainsi, le code errant ci-dessus affirme que, pour tous les types T<T>
où T,
Stateful
Logiquement, on peut le regarder comme suit
Affirmation
P
le type { on: boolean }
T
tels que T
est assignable à P
, la définition de Stateful<T>
ci-dessus est valideDémontrer par un contre-exemple
U
le type { on: boolean, value: number }
U
est assignable à P
-> par définitionStateful<U>
n'est pas valide -> par substitutionT
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>'
}
}
Commentaire le plus utile
Considérez ce qui se passe si vous écrivez ceci