mobx icon indicating copy to clipboard operation
mobx copied to clipboard

[Typescript] observer() type does not correctly infer props when part of an object

Open smirea opened this issue 2 years ago • 2 comments

Intended outcome:

observer() correctly passes inferred props types along

Actual outcome:

wrapping a component in observer() causes the props to be any

How to reproduce the issue:

Typescript playground example

import { observer } from 'mobx-react';

interface Shape<A> {
    fn: (args: A) => number | null;
}

function identity<X>(x: X): X { return x; }

const Plain: Shape<{ num: 123 }> = {
    fn: args => args.num, // works
}

const WithIdentity: Shape<{ num: 123 }> = {
    fn: identity(args => args.num), // works
}

const WithObserver: Shape<{ num: 123 }> = {
    fn: observer(args => args.num), // FAILS, "args" is typed as "any"
}

Versions

"mobx-react": "^7.5.2",
"@types/react": "^18.0.17",

Notes

After looking into it a bit I noticed that if you remove the React.ForwardRefExoticComponent<P> from the IReactComponent definition the types are inferred correctly

smirea avatar Aug 31 '22 20:08 smirea

Hi, thanks for the reproduction. I've removed React.ForwardRefExoticComponent but it didn't help. Link

The arg type is still any:

Screen Shot 2022-09-01 at 08 22 26

Could you elaborate why do you need making observer part of an object here?

kubk avatar Sep 01 '22 05:09 kubk

Could you elaborate why do you need making observer part of an object here?

I was writing a library where I need to export a component together with metadata and found defining an interface for the export was the least amount of friction. Example:

interface Field<Value> {
	title?: string;
	Component?: React.FC<{ field: { value: Value } }>; // field is observed
}

export const Numeric: Field<number> = {
	title: 'Number',
	Component: observer(({ field }) => <input type='number' value={field.value} />),
}

I've removed React.ForwardRefExoticComponent but it didn't help. Link

You need to import react: Link

smirea avatar Sep 01 '22 13:09 smirea