4

Given a react component that is generic on two properties, a load function returning type T, and the children (which is a single function taking a parameter of type T)...

class Test<T> extends React.Component<{
  load: () => T;
  children: (r: T) => JSX.Element;
}> {
  render() {
    return this.props.children(this.props.load());
  }
}

typescript is not able to infer the type of res from the return value of load, it defaults to type {}.

<Test load={() => ({ test: 'x' })}>
  {res =>
    <span>
      {res.test}
    </span>}
</Test>;

Is this a bug, or is typescript not able to infer based on return values -- as it looks like typing of JSX children is supported.

EDIT:

for background, the usecase is creating a "lazy" component which accepts load function which return a promise resolving to some further JSX.

1 Answer 1

2

Update: In the meantime TypeScript has been improved, such that the code given in the question automatically infers the type for res. I haven't checked which change was responsible for that, but I guess it happened somewhere around 3.0-3.3.


I think the problem is that your code gets transpiled to something similar to:

React.createElement(
  Test,
  {load: () => ({ test: 'x' })},
  res =>
    <span>
      {res.test}
    </span>
)

From that situation it is more clear that it would be very hard for the compiler/definitions to correctly infer the generic parameter. In your situation it would be enough to tip the compiler:

<Test load={() => ({ test: 'x' })}>
    {(res: { test: string }) =>
        <span>
            {res.test}
        </span>}
</Test>
Sign up to request clarification or add additional context in comments.

6 Comments

good point, maybe TS will add some JSX specific typing support for this stuff in the future.
I've just come across this issue and I'd like to do it in such a way that I don't have to specify the type on the children manually, is there any way to infer this now with the latest version of TypeScript please?
I've just checked it, at least by using Typescript 3.3 the code in the question works, automatically inferring the type for res.
For some reason it doesn't work when you add parameters to load method though: <Test load={({ test })=>({ test1: test })}>{({ test1 })=>(<span>{test1}</span>)}</Test> states that test1 that out of the Test component is of type any...grrr!
But then you are using a different type for load? Because the initial one (() => T) has no function argument.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.