Skip to content

Commit b543355

Browse files
authored
[react] Restore Class Component constructor using Context (DefinitelyTyped#72941)
1 parent b3fbfa5 commit b543355

File tree

6 files changed

+60
-27
lines changed

6 files changed

+60
-27
lines changed

types/prop-types/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ declare namespace PropTypes {
55
type ReactComponentLike =
66
| string
77
| ((props: any) => any)
8-
| (new(props: any) => any);
8+
| (new(props: any, context: any) => any);
99

1010
interface ReactElementLike {
1111
type: ReactComponentLike;

types/react-dual-listbox/react-dual-listbox-tests.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,29 +91,27 @@ const optionsChange = (selectedValues: Array<Option<string>>) => {};
9191
/>;
9292

9393
/** Filtering error examples. */
94+
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
9495
<DualListBox
9596
options={flatOptions}
9697
filter={{
9798
available: flatOptions.map(o => o.value),
9899
selected: [],
99100
}}
100-
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
101101
onFilterChange={() => {}}
102102
filterPlaceholder={""}
103-
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
104103
filterCallback={(option: Option<string>) => true}
105104
/>;
105+
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
106106
<DualListBox
107107
options={flatOptions}
108108
canFilter={false}
109109
filter={{
110110
available: flatOptions.map(o => o.value),
111111
selected: [],
112112
}}
113-
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
114113
onFilterChange={() => {}}
115114
filterPlaceholder={""}
116-
// @ts-expect-error You can not use filter properties when `canFilter` is not `true`.
117115
filterCallback={(option: Option<string>) => true}
118116
/>;
119117

types/react/index.d.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ declare namespace React {
135135
props: P,
136136
) => ReactNode | Promise<ReactNode>)
137137
// constructor signature must match React.Component
138-
| (new(props: P) => Component<any, any>);
138+
| (new(props: P, context: any) => Component<any, any>);
139139

140140
/**
141141
* Created by {@link createRef}, or {@link useRef} when passed `null`.
@@ -218,7 +218,7 @@ declare namespace React {
218218
type ElementRef<
219219
C extends
220220
| ForwardRefExoticComponent<any>
221-
| { new(props: any): Component<any> }
221+
| { new(props: any, context: any): Component<any> }
222222
| ((props: any) => ReactNode)
223223
| keyof JSX.IntrinsicElements,
224224
> = ComponentRef<C>;
@@ -928,7 +928,7 @@ declare namespace React {
928928
static propTypes?: any;
929929

930930
/**
931-
* If using the new style context, re-declare this in your class to be the
931+
* If using React Context, re-declare this in your class to be the
932932
* `React.ContextType` of your `static contextType`.
933933
* Should be used with type annotation or static contextType.
934934
*
@@ -947,6 +947,14 @@ declare namespace React {
947947

948948
// Keep in sync with constructor signature of JSXElementConstructor and ComponentClass.
949949
constructor(props: P);
950+
/**
951+
* @param props
952+
* @param context value of the parent {@link https://react.dev/reference/react/Component#context Context} specified
953+
* in `contextType`.
954+
*/
955+
// TODO: Ideally we'd infer the constructor signatur from `contextType`.
956+
// Might be hard to ship without breaking existing code.
957+
constructor(props: P, context: any);
950958

951959
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
952960
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
@@ -1118,7 +1126,14 @@ declare namespace React {
11181126
*/
11191127
interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
11201128
// constructor signature must match React.Component
1121-
new(props: P): Component<P, S>;
1129+
new(
1130+
props: P,
1131+
/**
1132+
* Value of the parent {@link https://react.dev/reference/react/Component#context Context} specified
1133+
* in `contextType`.
1134+
*/
1135+
context?: any,
1136+
): Component<P, S>;
11221137
/**
11231138
* Ignored by React.
11241139
* @deprecated Only kept in types for backwards compatibility. Will be removed in a future major release.
@@ -1158,7 +1173,7 @@ declare namespace React {
11581173
*/
11591174
type ClassType<P, T extends Component<P, ComponentState>, C extends ComponentClass<P>> =
11601175
& C
1161-
& (new(props: P) => T);
1176+
& (new(props: P, context: any) => T);
11621177

11631178
//
11641179
// Component Specs and Lifecycle

types/react/test/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,17 @@ declare const container: Element;
129129
}
130130
}
131131

132+
const SomeContext = React.createContext<Context>({ someValue: "default" });
132133
class ModernComponent extends React.Component<Props, State, Snapshot> implements MyComponent {
133134
// deprecated. Kept for backwards compatibility.
134135
static propTypes = {};
135136

136-
contextType: React.Context<Context>;
137-
context: Context = {};
137+
static contextType = SomeContext;
138+
context: Context;
139+
140+
constructor(props: Props, context: Context) {
141+
super(props, context);
142+
}
138143

139144
state = {
140145
inputValue: this.context.someValue,
@@ -829,11 +834,9 @@ const propsWithoutRef: React.PropsWithoutRef<UnionProps> = {
829834
// @ts-expect-error -- legacy context was removed
830835
Wrapper = (props, legacyContext: { foo: number }) => null;
831836

832-
// @ts-expect-error -- legacy context was removed
833837
Wrapper = class Exact extends React.Component<ExactProps> {
834-
constructor(props: ExactProps, legacyContext: { foo: number }) {
835-
// @ts-expect-error -- legacy context was removed
836-
super(props, legacyContext);
838+
constructor(props: ExactProps, definitelyNotLegacyContext: { foo: number }) {
839+
super(props, definitelyNotLegacyContext);
837840
}
838841
};
839842

types/react/ts5.0/index.d.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ declare namespace React {
135135
props: P,
136136
) => ReactElement<any, any> | null)
137137
// constructor signature must match React.Component
138-
| (new(props: P) => Component<any, any>);
138+
| (new(props: P, context: any) => Component<any, any>);
139139

140140
/**
141141
* Created by {@link createRef}, or {@link useRef} when passed `null`.
@@ -218,7 +218,7 @@ declare namespace React {
218218
type ElementRef<
219219
C extends
220220
| ForwardRefExoticComponent<any>
221-
| { new(props: any): Component<any> }
221+
| { new(props: any, context: any): Component<any> }
222222
| ((props: any) => ReactElement | null)
223223
| keyof JSX.IntrinsicElements,
224224
> = ComponentRef<C>;
@@ -929,7 +929,7 @@ declare namespace React {
929929
static propTypes?: any;
930930

931931
/**
932-
* If using the new style context, re-declare this in your class to be the
932+
* If using React Context, re-declare this in your class to be the
933933
* `React.ContextType` of your `static contextType`.
934934
* Should be used with type annotation or static contextType.
935935
*
@@ -948,6 +948,14 @@ declare namespace React {
948948

949949
// Keep in sync with constructor signature of JSXElementConstructor and ComponentClass.
950950
constructor(props: P);
951+
/**
952+
* @param props
953+
* @param context value of the parent {@link https://react.dev/reference/react/Component#context Context} specified
954+
* in `contextType`.
955+
*/
956+
// TODO: Ideally we'd infer the constructor signatur from `contextType`.
957+
// Might be hard to ship without breaking existing code.
958+
constructor(props: P, context: any);
951959

952960
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
953961
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
@@ -1117,7 +1125,13 @@ declare namespace React {
11171125
*/
11181126
interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
11191127
// constructor signature must match React.Component
1120-
new(props: P): Component<P, S>;
1128+
new(
1129+
props: P, /**
1130+
* Value of the parent {@link https://react.dev/reference/react/Component#context Context} specified
1131+
* in `contextType`.
1132+
*/
1133+
context?: any,
1134+
): Component<P, S>;
11211135
/**
11221136
* Ignored by React.
11231137
* @deprecated Only kept in types for backwards compatibility. Will be removed in a future major release.
@@ -1157,7 +1171,7 @@ declare namespace React {
11571171
*/
11581172
type ClassType<P, T extends Component<P, ComponentState>, C extends ComponentClass<P>> =
11591173
& C
1160-
& (new(props: P) => T);
1174+
& (new(props: P, context: any) => T);
11611175

11621176
//
11631177
// Component Specs and Lifecycle

types/react/ts5.0/test/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,17 @@ declare const container: Element;
129129
}
130130
}
131131

132+
const SomeContext = React.createContext<Context>({ someValue: "default" });
132133
class ModernComponent extends React.Component<Props, State, Snapshot> implements MyComponent {
133134
// deprecated. Kept for backwards compatibility.
134135
static propTypes = {};
135136

136-
contextType: React.Context<Context>;
137-
context: Context = {};
137+
static contextType = SomeContext;
138+
context: Context;
139+
140+
constructor(props: Props, context: Context) {
141+
super(props, context);
142+
}
138143

139144
state = {
140145
inputValue: this.context.someValue,
@@ -832,11 +837,9 @@ const propsWithoutRef: React.PropsWithoutRef<UnionProps> = {
832837
// @ts-expect-error -- legacy context was removed
833838
Wrapper = (props, legacyContext: { foo: number }) => null;
834839

835-
// @ts-expect-error -- legacy context was removed
836840
Wrapper = class Exact extends React.Component<ExactProps> {
837-
constructor(props: ExactProps, legacyContext: { foo: number }) {
838-
// @ts-expect-error -- legacy context was removed
839-
super(props, legacyContext);
841+
constructor(props: ExactProps, definitelyNotLegacyContext: { foo: number }) {
842+
super(props, definitelyNotLegacyContext);
840843
}
841844
};
842845

0 commit comments

Comments
 (0)