react-redux-typescript-guide: Hoc broken with typescript@3.2.1

Issuehunt badges

Got an issue with hoc and typescript 3.2.1, any idea of what’s missing

Based on latest master:

https://github.com/piotrwitek/react-redux-typescript-guide/blob/master/playground/src/hoc/with-state.tsx

Tsc will fail with

hoc/with-state.tsx:41:18 - error TS2322: Type '{ count: number; onIncrement: () => void; }' is not assignable to type 'IntrinsicAttributes & WrappedProps & { children?: ReactNode; }'.
  Property 'count' does not exist on type 'IntrinsicAttributes & WrappedProps & { children?: ReactNode; }'.

Any ideas ?


IssueHunt Summary

piotrwitek piotrwitek has been rewarded.

Backers (Total: $50.00)

Submitted pull Requests


Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I can’t adjust types to use Redux connect. Is it related?

const tx = ...;

export type Translator = typeof tx;

interface InjectedProps {
  t: Translator;
}

export const withTranslator = <BaseProps extends InjectedProps>(
  _BaseComponent: React.ComponentType<BaseProps>,
) => {
  // fix for TypeScript issues: https://github.com/piotrwitek/react-redux-typescript-guide/issues/111
  const BaseComponent = _BaseComponent as React.ComponentType<InjectedProps>;

  type HocProps = Subtract<BaseProps, InjectedProps>;
  type TStateProps = ReturnType<typeof mapStateToProps>;

  class Hoc extends React.Component<HocProps> {
    static displayName = `injectL10n(${BaseComponent.name})`;
    static readonly WrappedComponent = BaseComponent;

    render() {
      const { ...restProps } = this.props;
      return <BaseComponent t={tx} {...restProps} />;
    }
  }

  const mapStateToProps = (state: RootState) => ({
    language: state.l10n.language,
  });
  
  // type error:
  return connect<TStateProps, {}, HocProps, RootState>(mapStateToProps)(Hoc);
};

Error:

Argument of type 'typeof Hoc' is not assignable to parameter of type 'ComponentType<Matching<{ language: string; } & DispatchProp<AnyAction>, Pick<BaseProps, SetDifference<keyof BaseProps, "t">>>>'.
  Type 'typeof Hoc' is not assignable to type 'ComponentClass<Matching<{ language: string; } & DispatchProp<AnyAction>, Pick<BaseProps, SetDifference<keyof BaseProps, "t">>>, any>'.
    Types of parameters 'props' and 'props' are incompatible.
      Type 'Matching<{ language: string; } & DispatchProp<AnyAction>, Pick<BaseProps, SetDifference<keyof BaseProps, "t">>>' is not assignable to type 'Readonly<Pick<BaseProps, SetDifference<keyof BaseProps, "t">>>'.
        Type 'P extends "dispatch" | "language" ? ({ language: string; } & DispatchProp<AnyAction>)[P] extends Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] ? Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] : ({ ...; } & DispatchProp<...>)[P] : Pick<...>[P]' is not assignable to type 'BaseProps[P]'.
          Type 'Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] | (({ language: string; } & DispatchProp<AnyAction>)[P] extends Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] ? Pick<...>[P] : ({ ...; } & DispatchProp<...>)[P])' is not assignable to type 'BaseProps[P]'.
            Type '({ language: string; } & DispatchProp<AnyAction>)[P] extends Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] ? Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P] : ({ ...; } & DispatchProp<...>)[P]' is not assignable to type 'BaseProps[P]'.
              Type '({ language: string; } & DispatchProp<AnyAction>)[P] | Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[P]' is not assignable to type 'BaseProps[P]'.
                Type '({ language: string; } & DispatchProp<AnyAction>)[P]' is not assignable to type 'BaseProps[P]'.
                  Type '{ language: string; } & DispatchProp<AnyAction>' is not assignable to type 'BaseProps'.
                    Type 'SetDifference<keyof BaseProps, "t"> extends "dispatch" | "language" ? ({ language: string; } & DispatchProp<AnyAction>)[("dispatch" & SetDifference<keyof BaseProps, "t">) | ("language" & SetDifference<...>)] extends Pick<...>[("dispatch" & SetDifference<...>) | ("language" & SetDifference<...>)] ? Pick<...>[("dispat...' is not assignable to type 'BaseProps[P]'.
                      Type '(({ language: string; } & DispatchProp<AnyAction>)[("dispatch" & SetDifference<keyof BaseProps, "t">) | ("language" & SetDifference<keyof BaseProps, "t">)] extends Pick<BaseProps, SetDifference<...>>[("dispatch" & SetDifference<...>) | ("language" & SetDifference<...>)] ? Pick<...>[("dispatch" & SetDifference<...>) ...' is not assignable to type 'BaseProps[P]'.
                        Type '({ language: string; } & DispatchProp<AnyAction>)[("dispatch" & SetDifference<keyof BaseProps, "t">) | ("language" & SetDifference<keyof BaseProps, "t">)] extends Pick<BaseProps, SetDifference<...>>[("dispatch" & SetDifference<...>) | ("language" & SetDifference<...>)] ? Pick<...>[("dispatch" & SetDifference<...>) |...' is not assignable to type 'BaseProps[P]'.
                          Type '({ language: string; } & DispatchProp<AnyAction>)[("dispatch" & SetDifference<keyof BaseProps, "t">) | ("language" & SetDifference<keyof BaseProps, "t">)] | Pick<BaseProps, SetDifference<...>>[("dispatch" & SetDifference<...>) | ("language" & SetDifference<...>)]' is not assignable to type 'BaseProps[P]'.
                            Type '({ language: string; }["dispatch" & SetDifference<keyof BaseProps, "t">] & DispatchProp<AnyAction>["dispatch" & SetDifference<keyof BaseProps, "t">]) | ({ language: string; }["language" & SetDifference<...>] & DispatchProp<...>["language" & SetDifference<...>])' is not assignable to type 'BaseProps[P]'.
                              Type '{ language: string; }["dispatch" & SetDifference<keyof BaseProps, "t">] & DispatchProp<AnyAction>["dispatch" & SetDifference<keyof BaseProps, "t">]' is not assignable to type 'BaseProps[P]'.
                                Type 'Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[string] | Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[number] | Pick<BaseProps, SetDifference<keyof BaseProps, "t">>[symbol]' is not assignable to type 'BaseProps[P]'.
                                  Type 'BaseProps[string]' is not assignable to type 'BaseProps[P]'.
                                    Type 'string' is not assignable to type 'P'.
                                      'string' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'.

Thanks.

The issue is fixed using:

  {...(restProps as BaseProps)}

Full example:

import React from 'react';
import { Diff } from 'utility-types';

interface InjectedProps {
  count: number;
  onIncrement: () => void;
}

export const withState = <BaseProps extends InjectedProps>(
  BaseComponent: React.ComponentType<BaseProps>
) => {
  type HocProps = Diff<BaseProps, InjectedProps> & {
    initialCount?: number;
  };
  type HocState = {
    readonly count: number;
  };

  return class Hoc extends React.Component<HocProps, HocState> {
    static displayName = `withState(${BaseComponent.name})`;
    static readonly WrappedComponent = BaseComponent;

    readonly state: HocState = {
      count: Number(this.props.initialCount) || 0,
    };

    handleIncrement = () => {
      this.setState({ count: this.state.count + 1 });
    };

    render() {
      const { ...restProps } = this.props;
      const { count } = this.state;

      return (
        <BaseComponent
          count={count}
          onIncrement={this.handleIncrement}
          {...(restProps as BaseProps)} // <= HERE
        />
      );
    }
  };
};