Versión de TypeScript: 2.2.2
Puede que esté malinterpretando cómo funcionan los genéricos (si es así, indíqueme la dirección correcta), pero esto parece un error.
Código
// 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'.
}
}
Comportamiento esperado:
En la clase Component
en el ejemplo anterior no causa errores cuando se usa la interfaz BaseState
directamente. Espero el mismo comportamiento de la clase GenericComponent
ya que el genérico State
extiende explícitamente BaseState
.
Comportamiento real:
En su lugar, obtengo el siguiente error relacionado con this.setState({ on: value > 0 });
: "El argumento de tipo '{on: boolean;}' no se puede asignar al parámetro de tipo 'State'".
Considere lo que sucede si escribe esto
var t = new GenericComponent<{on: boolean, thing: string}>();
t.onInput({ value: 30 });
t.state.thing.substr(0); // 'thing' property should exist, but doesn't
A continuación, se muestra un ejemplo simplificado:
class Stateful<State extends { on: boolean }> {
state: State = {
on: true
}; // error
}
La razón por la que esto no funciona es que solo será válido cuando Stateful
se instancia con un argumento de tipo exactamente equivalente a { on: boolean }
.
Básicamente, _existe_ un tipo T
, que satisface las restricciones del argumento de tipo de Stateful
, de modo que la instanciación es válida pero esto no es válido para todos_ los tipos T
donde T
satisface la restricción del argumento de tipo de Stateful
.
Entonces, el código errante anterior afirma que, para todos los tipos T<T>
donde T,
Stateful
Lógicamente, podemos mirarlo de la siguiente manera
Afirmación
P
el tipo { on: boolean }
T
manera que T
se pueda asignar a P
, la definición de Stateful<T>
anterior es válidaRefutar con contraejemplo
U
el tipo { on: boolean, value: number }
U
se puede asignar a P
-> por definiciónStateful<U>
no es válido -> por sustituciónT
tal que T
se puede asignar a P
y Stateful<T>
es una instanciación no válida -> por implicación@RyanCavanaugh @aluanhaddad Shoot, lo sabía. Simplemente me confundí mientras trataba de resumir el problema en algo más simple. Así que intentemos eso de nuevo. ¿Qué pasa en este caso con el uso de un parcial? Sigo recibiendo un error similar.
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>'
}
}
Comentario más útil
Considere lo que sucede si escribe esto