рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕рдВрд╕реНрдХрд░рдг: 2.2.2
рдореИрдВ рдмрд╕ рдЧрд▓рддрдлрд╣рдореА рд╣реЛ рд╕рдХрддреА рд╣реИ рдХрд┐ рдЬреЗрдирд░рд┐рдХ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ (рдпрджрд┐ рдРрд╕рд╛ рд╣реИ рддреЛ рдХреГрдкрдпрд╛ рдореБрдЭреЗ рд╕рд╣реА рджрд┐рд╢рд╛ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВ), рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдмрдЧ рдЬреИрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИред
рдХреЛрдб
// 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'.
}
}
рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░:
рдКрдкрд░ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ Component
рд╡рд░реНрдЧ рдореЗрдВ BaseState
рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╕реАрдзреЗ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдкрд░ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рдореИрдВ GenericComponent
рд╡рд░реНрдЧ рд╕реЗ рд╕рдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдЙрдореНрдореАрдж рдХрд░рддрд╛ рд╣реВрдВ рдХреНрдпреЛрдВрдХрд┐ State
рдЬреЗрдиреЗрд░рд┐рдХ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ BaseState
рдлреИрд▓реА рд╣реБрдИ рд╣реИред
рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╡реНрдпрд╡рд╣рд╛рд░:
рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдореБрдЭреЗ this.setState({ on: value > 0 });
рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд┐рдореНрди рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ: "рдЯрд╛рдЗрдк рдСрдлрд╝ {on: рдмреБрд▓рд┐рдпрди;}" рдХрд╛ рддрд░реНрдХ 'рдЯрд╛рдЗрдк' рд╕реНрдЯреЗрдЯ рдХреЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реИред "
рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ
var t = new GenericComponent<{on: boolean, thing: string}>();
t.onInput({ value: 30 });
t.state.thing.substr(0); // 'thing' property should exist, but doesn't
рдпрд╣рд╛рдБ рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
class Stateful<State extends { on: boolean }> {
state: State = {
on: true
}; // error
}
рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЗрд╕рдХрд╛ рдХрд╛рд░рдг рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдХрднреА рднреА рдХреЗрд╡рд▓ рддрднреА рдорд╛рдиреНрдп рд╣реЛрдЧрд╛ рдЬрдм Stateful
рдХрд╛ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХреЗ рддрд░реНрдХ рдХреЗ рд╕рд╛рде рддреНрд╡рд░рд┐рдд рд░реВрдк рд╕реЗ { on: boolean }
рдмрд░рд╛рдмрд░ рд╣реЛред
рдЕрд╕рд▓ рдореЗрдВ, _there exists_ рдПрдХ рдЯрд╛рдЗрдк T
, рдХреА рдХрдореА рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ Stateful
рдХреЗ рдкреНрд░рдХрд╛рд░ рддрд░реНрдХ рдРрд╕реА рд╣реИ рдХрд┐ рдЗрдиреНрд╕реНрдЯреЗрдиреНрд╢рд┐рдпрд╢рди рдорд╛рдиреНрдп рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ all_ рдкреНрд░рдХрд╛рд░ _for рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ T
рдЬрд╣рд╛рдВ T
Stateful
рдкреНрд░рдХрд╛рд░ рдХреЗ рддрд░реНрдХ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рддрд╛ рд╣реИред
рддреЛ рдКрдкрд░ рдЧрд▓рдд рдХреЛрдб рд╕рднреА рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП T<T>
рдЬрд╣рд╛рдВ T,
рд╕реНрдЯреЗрдЯрдлреБрд▓ рд╣реИ
рддрд╛рд░реНрдХрд┐рдХ рд░реВрдк рд╕реЗ, рд╣рдо рдЗрд╕реЗ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ
рдЕрднрд┐рдХрдерди
P
{ on: boolean }
рдЯрд╛рдЗрдк рд╣реЛрдиреЗ рджреЗрдВT
рдРрд╕реЗ рд╣реИрдВ рдХрд┐ T
P
, Stateful<T>
рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рд╡реИрдз рд╣реИредрдХрд╛рдЙрдВрдЯрд░ рдЙрджрд╛рд╣рд░рдг рджреНрд╡рд╛рд░рд╛ рдкреНрд░рдЪреНрдЫрдиреНрди
U
{ on: boolean, value: number }
рдЯрд╛рдЗрдк рд╣реЛрдиреЗ рджреЗрдВU
рдкрд░рд┐рднрд╛рд╖рд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ P
-> рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реИStateful<U>
рдЕрд╡реИрдз рд╣реИ -> рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рджреНрд╡рд╛рд░рд╛T
рдПрдХ рдкреНрд░рдХрд╛рд░ рдореМрдЬреВрдж рд╣реИ рдХрд┐ T
P
рдФрд░ Stateful<T>
рдПрдХ рдЕрд╡реИрдз рддрд╛рддреНрдХрд╛рд▓рд┐рдХрддрд╛ рд╣реИ - рдирд┐рд╣рд┐рддрд╛рд░реНрде рджреНрд╡рд╛рд░рд╛@RyanCavanaugh @aluanhaddad рд╢реВрдЯ, рдореБрдЭреЗ рдкрддрд╛ рдерд╛ рдХрд┐ред рдореИрдВ рдмрд╕ рдХреБрдЫ рдЖрд╕рд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдорд╕реНрдпрд╛ рдХреЛ рджреВрд░ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реБрдП рднреНрд░рдорд┐рдд рд╣реЛ рдЧрдпрд╛ред рддреЛ рдЪрд▓рд┐рдП рдлрд┐рд░ рд╕реЗ рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЖрдВрд╢рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛? рдореБрдЭреЗ рдЕрднреА рднреА рдЗрд╕реА рддрд░рд╣ рдХреА рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИред
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>'
}
}
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ