question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. Itย collects links to all the places you might be looking at while hunting down a tough bug.

And, if youโ€™re still stuck at the end, weโ€™re happy to hop on a call to see how we can help out.

Pipe function + `React.memo` returns component with `any` props

See original GitHub issue

TypeScript Version: 3.9.2

Search Terms: generic pipe pipeWith react memo HOC props any

Code

import * as React from 'react';

declare function pipeWith<A, B>(a: A, ab: (a: A) => B): B;

type Props = { foo: number };
declare const MyComponent: React.FunctionComponent<Props>;

// โœ… correct props type
// React.NamedExoticComponent<Props>
const r1 = React.memo(MyComponent);

// โŒ `any` props type
// React.MemoExoticComponent<React.ComponentType<any>>
const r2 = pipeWith(MyComponent, React.memo);

// Workaround
// โœ… correct props type
// React.NamedExoticComponent<Props>
const r3 = pipeWith(MyComponent, (C) => React.memo(C));

Using latest version of @types/react (at the time of writing: 16.9.35).

Expected behavior:

See above.

Actual behavior:

See above.

Playground Link:

https://stackblitz.com/edit/react-ts-4ih6jn

Related Issues:

https://github.com/microsoft/TypeScript/issues/25637, although that was closed as a duplicate of an issue which has since been closed (https://github.com/microsoft/TypeScript/issues/10957), so I decided to post a new issue.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
dragomirtitiancommented, Jun 22, 2020

@RyanCavanaugh Hope this helps:

// The presence of any overloads confuses inference, leave just one of them in and everything works
declare function memo<T>(Component: T): T;
declare function memo<T>(Component: T): T;

declare function pipeWith<A, B>(a: A, ab: (a: A) => B): B;

type Props = { foo: number };
declare const MyComponent: Props;

// โœ… correct props type
// Props
const r1 = memo(MyComponent);

// โŒ `unknown` props type
// unknown
const r2 = pipeWith(MyComponent, memo);

// Workaround
// โœ… correct props type
// Props
const r3 = pipeWith(MyComponent, (C) => memo(C));

Playground Link

Just the presence of any overloads will confuse the inference on the original use case. Leave just the one signature and everything works as expected.

0reactions
OliverJAshcommented, Apr 30, 2021

Iโ€™m running into this all of the time, not just when using React.memo.

Example using Object.values:

declare function pipe<A, B>(a: A, ab: (a: A) => B): B;

// Type of `value1` is `any[]`, expected `(string | number)[]`
const value1 = pipe({ foo: 1, bar: 'abc' }, Object.values);
// Workaround:
const value2 = pipe({ foo: 1, bar: 'abc' }, (x) => Object.values(x));

Playground here.

Hereโ€™s another example when using RxJS v7 (7.0.0). Iโ€™ve reduced the test case down further in this playground.

import { lastValueFrom, of } from 'rxjs';
import { tap } from 'rxjs/operators';

declare function pipe<A, B>(a: A, ab: (a: A) => B): B;

//
// `of` example
//

{
    // Type of `value1` is `Observable<never>`, expected `Observable<string>`
    const value1 = pipe('foo', of);
    // Workaround:
    const value2 = pipe('foo', (x) => of(x));
}

//
// `lastValueFrom` example
//

pipe(of('foo'), lastValueFrom).then((x) => {
    // Type of `x` is `unknown`, expected `string`
    x;
});
// Workaround:
pipe(of('foo'), (ob) => lastValueFrom(ob)).then((x) => {
    x;
});

//
// `tap` example
//

declare const hof: <T>(g: (t: T) => void) => (t: T) => void;

of('foo').pipe(
    tap(
        hof((x) => {
            // Type of `x` is `unknown`, expected `string`
            x;
        }),
    ),
);
// Workaround:
of('foo').pipe(
    tap((value) =>
        pipe(
            value,
            hof((x) => {
                x;
            }),
        ),
    ),
);
Read more comments on GitHub >

github_iconTop Results From Across the Web

memo - React Docs
My component re-renders when a prop is an object, array, or function ... The memo does not modify this component, but returns a...
Read more >
React.memo, useMemo, Lists (keys) | by Caio ... - Medium
It is worth saying that if a component receives a function as a prop, you need to use the useCallback hook, so that...
Read more >
Use React.memo() wisely
Invokes the comparison function to determine whether the previous and next props are equal; Because props comparison almost always returns falseย ...
Read more >
How to use the react.memo function in react - Snyk
Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues...
Read more >
When To Use React.memo() โ€” And When Not To | by Ellon
When React components are wrapped with React.memo(), React renders the component and memoizes the result. If the component's props are the sameย ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found