mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-08-12 04:50:18 +00:00
feat(react): improve props and state typesafety on Component
- fix(react): remove failing expectation on TS 2.6 - chore(react): add myself to contributors
This commit is contained in:
Vendored
+17
-3
@@ -17,6 +17,7 @@
|
||||
// Ferdy Budhidharma <https://github.com/ferdaber>
|
||||
// Johann Rakotoharisoa <https://github.com/jrakotoharisoa>
|
||||
// Olivier Pascal <https://github.com/pascaloliv>
|
||||
// Martin Hochel <https://github.com/hotell>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.6
|
||||
|
||||
@@ -281,13 +282,18 @@ declare namespace React {
|
||||
// tslint:disable-next-line:no-empty-interface
|
||||
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }
|
||||
class Component<P, S> {
|
||||
constructor(props: Readonly<P>);
|
||||
/**
|
||||
* @deprecated
|
||||
* https://reactjs.org/docs/legacy-context.html
|
||||
*/
|
||||
constructor(props: P, context?: any);
|
||||
|
||||
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
|
||||
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
|
||||
// Also, the ` | S` allows intellisense to not be dumbisense
|
||||
setState<K extends keyof S>(
|
||||
state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
|
||||
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
|
||||
callback?: () => void
|
||||
): void;
|
||||
|
||||
@@ -299,9 +305,17 @@ declare namespace React {
|
||||
// always pass children as variadic arguments to `createElement`.
|
||||
// In the future, if we can define its call signature conditionally
|
||||
// on the existence of `children` in `P`, then we should remove this.
|
||||
props: Readonly<{ children?: ReactNode }> & Readonly<P>;
|
||||
state: Readonly<S>;
|
||||
readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
|
||||
readonly state: null | Readonly<S>;
|
||||
/**
|
||||
* @deprecated
|
||||
* https://reactjs.org/docs/legacy-context.html
|
||||
*/
|
||||
context: any;
|
||||
/**
|
||||
* @deprecated
|
||||
* https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
|
||||
*/
|
||||
refs: {
|
||||
[key: string]: ReactInstance
|
||||
};
|
||||
|
||||
@@ -54,6 +54,72 @@ declare const container: Element;
|
||||
//
|
||||
// Top-Level API
|
||||
// --------------------------------------------------------------------------
|
||||
{
|
||||
interface State {
|
||||
inputValue: string;
|
||||
seconds: number;
|
||||
}
|
||||
/**
|
||||
* This is a "pre EcmaScript class property era" style of setting state within constructor.
|
||||
* This occurs also if you need to provide som logic before mounting your component.
|
||||
* To mitigate this error you need to provide state property definition upfront.
|
||||
*/
|
||||
class SettingStateFromCtorComponent extends React.Component<Props, State, Snapshot> {
|
||||
// uncomenting this fixes the error :)
|
||||
// state: State;
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
// $ExpectError
|
||||
this.state = {
|
||||
inputValue: 'hello'
|
||||
};
|
||||
}
|
||||
render() { return null; }
|
||||
}
|
||||
|
||||
class BadlyInitializedState extends React.Component<Props, State, Snapshot> {
|
||||
// ExpectError -> this throws error on TS 2.6
|
||||
// state = {
|
||||
// secondz: 0,
|
||||
// inputValuez: 'hello'
|
||||
// };
|
||||
}
|
||||
class BetterPropsAndStateChecksComponent extends React.Component<Props, State, Snapshot> {
|
||||
render() { return null; }
|
||||
componentDidMount() {
|
||||
// $ExpectError
|
||||
console.log(this.state.inputValue);
|
||||
}
|
||||
mutateState() {
|
||||
// $ExpectError
|
||||
this.state = {
|
||||
inputValue: 'hello'
|
||||
};
|
||||
|
||||
// Even if state is not set, this is allowed by React
|
||||
this.setState({inputValue: 'hello'});
|
||||
this.setState((prevState, props) => {
|
||||
// $ExpectError
|
||||
props = {foo: 'nope'};
|
||||
// $ExpectError
|
||||
props.foo = 'nope';
|
||||
|
||||
return { inputValue: prevState.inputValue + ' foo' };
|
||||
});
|
||||
}
|
||||
mutateProps() {
|
||||
// $ExpectError
|
||||
this.props = {};
|
||||
// $ExpectError
|
||||
this.props = {
|
||||
key: 42,
|
||||
ref: "myComponent42",
|
||||
hello: "world",
|
||||
foo: 42
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ModernComponent extends React.Component<Props, State, Snapshot>
|
||||
implements MyComponent, React.ChildContextProvider<ChildContext> {
|
||||
@@ -682,6 +748,7 @@ React.createFactory(TransitionGroup)({ component: "div" });
|
||||
// The SyntheticEvent.target.value should be accessible for onChange
|
||||
// --------------------------------------------------------------------------
|
||||
class SyntheticEventTargetValue extends React.Component<{}, { value: string }> {
|
||||
state: { value: string };
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
this.state = { value: 'a' };
|
||||
|
||||
@@ -141,6 +141,10 @@ class ComponentWithNewLifecycles extends React.Component<NewProps, NewState, { b
|
||||
return { bar: `${nextProps.foo}bar` };
|
||||
}
|
||||
|
||||
state = {
|
||||
bar: 'foo'
|
||||
};
|
||||
|
||||
getSnapshotBeforeUpdate(prevProps: Readonly<NewProps>) {
|
||||
return { baz: `${prevProps.foo}baz` };
|
||||
}
|
||||
@@ -160,6 +164,10 @@ class PureComponentWithNewLifecycles extends React.PureComponent<NewProps, NewSt
|
||||
return { bar: `${nextProps.foo}bar` };
|
||||
}
|
||||
|
||||
state = {
|
||||
bar: 'foo'
|
||||
};
|
||||
|
||||
getSnapshotBeforeUpdate(prevProps: Readonly<NewProps>) {
|
||||
return { baz: `${prevProps.foo}baz` };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user