Reputation: 341
This is React + Typescript issue. I'm having a component that uses two generics for props and state.
interface Props {
foo: string;
}
interface State {
bar: string;
}
class Foo<
P extends Props = Props,
S extends State = State
> extends React.Component<P, S> {
constructor(props: P) {
super(props);
this.state = { bar: "asd" };
}
}
The assigment to this.state
in constructor is found to be an error with message:
Type '{ bar: "asd"; }' is not assignable to type 'Readonly(S)'
When you remove the generic from class declaration and pass State
interface directly to React.Component<P, State>
the everything is OK.
My question is how to avoid such error ? I need to initialize state in such manner that will validate known state parameters (like bar in this example) but will allow to specify additional properties.
Upvotes: 0
Views: 2225
Reputation: 341
As @Juraj Kocan wrote in his answer. The problem is created because:
you try to initialize generic type, this is wrong since you can extend this type and initialization won't be correct
Meanwhile I found that I can deal with it by spreading state in constructor:
interface Props {
foo: string;
}
interface State {
bar: string;
}
class Foo<
P extends Props = Props,
S extends State = State
> extends React.Component<P, S> {
constructor(props: P) {
super(props);
this.state = { ...this.state, bar: "asd" };
}
}
You can also do it without constructor:
interface Props {
foo: string;
}
interface State {
bar: string;
}
class Foo<
P extends Props = Props,
S extends State = State
> extends React.Component<P, S> {
state:S = { ...this.state, bar: "asd" };
}
The latter solution was even better because spreading this.state in constructor made other errors appear where I used immutability-helper. Spreading in constructor made TypeScript lose track of index properties in update() function of immutability-helper.
Upvotes: 1
Reputation: 2878
you try to initialize generic type, this is wrong since you can extend this type and initialization won't be correct
example:
const instance = new Foo<Props, { otherRequiredProperty: string } & State>({ foo: '' });
cosnt otherProperty = instance.state.otherRequiredProperty
so i said that state type will have 2 required props but in your class you initialized with only bar...
you can create interface with required props and other optional if this is your point
interface Props {
foo: string;
}
interface State {
bar: string;
[key: string]: string;
}
export class Foo extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
bar: '',
};
this.setState({
anything: '', // no error
});
}
}
this will not throw error and you can still add another property in to your state
Upvotes: 1
Reputation: 84
try this:
class Foo extends React.PureComponent<P, S> {
state: State; //Add this line
constructor(props: P) {
super(props);
this.state = { bar: "asd" };
}
}
Upvotes: 0