-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React :: partial State on setState #11740
Conversation
@bbenezech, @joshaber, @neelance and @DanielRosenwasser can you please review this change? |
Wow, it'd be great if we didn't have to pass all of I'm not sure I understand how/why this works, though. Could you explain it? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have mixed results with (ironically) optional State properties:
// with TS2.0.3, StrictNullChecks to true,
// removing first noisy setState overloading (irrelevant here) `setState(f: (prevState: S, props: P) => S, callback?: () => any): void;`
interface S {
a: string,
b: string
}
class Test extends React.PureComponent<{}, S> {
componentDidMount() {
// [ts] The type argument for type parameter 'S' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
// Type argument candidate 'S' is not a valid type argument because it is not a supertype of candidate '{ a: string; }'.
// Property 'b' is missing in type '{ a: string; }'.
// (method) React.Component<{}, S>.setState<S>(this: React.Component<{}, S>, state: S, callback?: (() => any) | undefined): void
this.setState({
a: 'test'
})
// [ts] Argument of type '{ a: string; }' is not assignable to parameter of type 'S'.
// Property 'b' is missing in type '{ a: string; }'.
this.setState<S>({
a: 'test'
})
// passes
this.setState({
a: undefined,
b: 'test'
})
// passes
this.setState({
a: 'test',
b: 'test'
})
}
}
sorry, should read interface S {
a: string|undefined,
b: string
} (dumb last second change, cannot edit review) |
@joshaber What I understand is that typescript infers that the State of the component is a supertype of the state parameter, this is what the error message says: interface ComponentState {
a: string;
}
export class Test extends React.PureComponent<{}, ComponentState> {
componentDidMount() {
// [ts] The type argument for type parameter 'S' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
// Type argument candidate 'ComponentState' is not a valid type argument because it is not a supertype of candidate '{ wrong: string; }'.
// Object literal may only specify known properties, and 'wrong' does not exist in type 'ComponentState'.
// (property) wrong: string
this.setState({
wrong: 'test'
});
}
} @bbenezech I had to remove all optional properties from the tests. In my code I'm not using them, instead I supply default blank/empty values. |
I encourage you not to merge this. Apart from the optional pb, which is a big one, It means the inference on S is not working as intended. |
I agree, especially as TypeScript is working on real support for subsets. |
@RyanCavanaugh can you glance at this? |
It still looks like you have to pass in the full state in most cases as @bbenezech mentioned above. Why not try something like setState<PartialState, ActualState extends PartialState>(this: Component<P, ActualState>, state: PartialState, callback?: () => any) |
@DanielRosenwasser Interesting approach, but no dice. interface S {
a?: string,
b: string
}
// Type 'string | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'.
this.setState({
a: 'test'
})
// Type 'string | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'.
this.setState({
a: 'test',
b: 'test'
})
// Property b is missing from type S
this.setState({
a: 'test'
} as S)
// this works
this.setState({
a: 'test',
b: 'test'
} as S) Sorry folks :( |
Luckily we're looking into non-hacky ways of declaring this. |
https://github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/react#the-type-of-setstate-is-incorrect
Changing React.Component setState from
to
removes the need to define State properties as optional (
?
).Important change is in
react/index.d.ts
other changes are just fixing tests for other components.This may not be the final solution after typescript adds proper support for partial types, but I wanted to discuss this solution with the community.