-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Unexpected props type for React component with constructor #25581
Comments
I tried to further narrow down the issue. This is where I got to: // src/main-tsx.tsx
declare function getComponentProps<P>(
component: React.ComponentType<P> | React.Component<P>,
): P;
type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never
type FooProps = { foo: string };
class Foo extends React.Component<FooProps> {
// props param is implicitly `any`
// Workaround: if we annotate the param, `FooPropsInferred2` will have the expected type
// constructor(props: FooProps) {
constructor(props) {
super(props);
}
}
declare const fooProps: FooProps;
// $ExpectType FooProps
fooProps;
declare const fooProps2: GetComponentProps<Foo>;
// $ExpectType FooProps
fooProps2;
const x = getComponentProps(Foo);
declare const fooProps3: typeof x;
// $ExpectType FooProps
fooProps3;
|
I narrowed the issue down further and removed the React dependency: class Component<P> {
props: P;
constructor(props: P) {
this.props = props;
}
}
interface ComponentClass<P> {
new (props: P): Component<P>;
}
declare function getComponentProps<P>(
component: ComponentClass<P>,
): P;
declare function getComponentProps2<T>(
component: T,
): T extends ComponentClass<infer P> ? P : never;
type FooProps = { foo: string };
class Foo extends Component<FooProps> {
// props param is implicitly `any`
// Workaround: if we annotate the param, `FooPropsInferred2` will have the expected type
// constructor(props: FooProps) {
constructor(props) {
super(props);
}
}
const x = getComponentProps(Foo); // any
const y = getComponentProps2(Foo); // FooProps In each case, there are two inferences for I assume the inference was implemented the way it was for a reason, though I don't know the reason. I think the solution to this case is "use |
thanks @mattmccutchen for the detailed analysis. implicit I think the underlying issue here is an expectation that derived class methods, properties, and constuctors "inherit" their types from the base class. that is unfortunately not the case, this is tracked by #23911 (previously discussed in #1373, #3667, and #10610). |
This is a surprising inconsistency. Is this intentional for some reason, or is it a bug? |
I just tried this on TypeScript 2.9.2 and the discrepancy does not go away when |
You are right. I don't know what I was thinking before. New analysis: in both cases, const signature = context.signature;
if (signature) {
if (inference.contraCandidates) {
// If we have contravariant inferences we find the best common subtype and treat
// that as a single covariant candidate.
inference.candidates = append(inference.candidates, getContravariantInference(inference));
inference.contraCandidates = undefined;
}
if (inference.candidates) {
inferredType = getCovariantInference(inference, context, signature);
}
// ...
}
else {
inferredType = getTypeFromInference(inference);
} where: function getTypeFromInference(inference: InferenceInfo) {
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
emptyObjectType;
} The conclusion is still the same: I assume the inference algorithm was designed this way for a reason (though I'm not familiar with it), and you should use |
Closing as apparently this is working as intended. |
TypeScript Version: 2.9.2
Search Terms: react component props type constructor implicit any hoc
Code
… unless we comment out the constructor, or annotate the
props
param:Why does the presence of the constructor change the props type only after the component is ran through the HOC?
The text was updated successfully, but these errors were encountered: